// FaceFinder.cpp: implementation of the CFaceFinder class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "FaceFinder.h"
//#include "resource.h"
#include <math.h>
//#include "facesubspace.h"
//#include "bmp.h"
//#define UOTPUT_DETECTION_RESULT
// calculate the overlap length between two lines
// add by QiaoYU
int reg_count=0;

int NUM_IMG = 0;
//CPCASubSpace  PCA;
int MirType[7] = {0, 1, 2,3,4,6,5};
int MirSign[7] = {1, -1, 1,1,-1,1,1};

int   hSobel_Template[9]={-1 , 0 , 1,
						  -2 , 0 , 2,
						  -1 , 0 , 1};

int   vSobel_Template[9]={-1 ,-2 ,-1,
						   0 , 0 , 0,
						   1 , 2 , 1};



inline int OverlapLine(int x1, int x2, int y1,int y2)
{
	if(x1 > x2)
	{
		int t = x1;
		x1 = x2;
		x2 = t;
	}

	if(y1>y2)
	{
		int t=y1;
		y1=y2;
		y2=t;
	}

	// no overlap image
	if(x2<=y1 || x1>=y2)
		return 0;
	
	if(x2<=y2)
	{
		if(x1>=y1)
			return x2-x1;
		else
			return x2-y1;
	}
	else
	{
		if(y1>=x1)
			return y2-y1;
		else
			return y2-x1;
	}

	return 0;
}

// calculate the overlap area between two rectangles

inline int OverlapRect(int top,int bottom,int left,int right,int top1,int bottom1,int left1,int right1)
{
	int l1 = OverlapLine(top,bottom,top1,bottom1);
	int l2 = OverlapLine(left,right,left1,right1);

	return l1*l2;
}

#define SAFE_RELEASE(x) if(x) {delete x; x = NULL;}
#define NULL_POINTER(x) x = NULL
#ifndef MIN
#define MIN(x, y) (x) < (y) ? (x) : (y)
#endif
#ifndef MAX
#define MAX(x, y) (x) >= (y) ? (x) : (y)
#endif
void SAFE_RELEASE2(int** ppImg, int nDim)
{
	if(ppImg)
	{
		for(int i = 0; i < nDim; i++)
			SAFE_RELEASE(ppImg[i]);
		SAFE_RELEASE(ppImg);
	}
}

void SAFE_RELEASE3(BYTE** ppImg, int nDim)
{
	if(ppImg)
	{
		for(int i = 0; i < nDim; i++)
			SAFE_RELEASE(ppImg[i]);
		SAFE_RELEASE(ppImg);
	}
}


int** New_2D(int nDim1, int nDim2)
{
	int** ppImg;
	
	ppImg = new int*[nDim1];
	ASSERT(ppImg);

	for(int i = 0; i < nDim1; i++)
	{
		ppImg[i] = new int[nDim2];
	}

	return ppImg;
}

BYTE** New_2D2(int nDim1, int nDim2)
{
	BYTE** ppImg; 

	ppImg = new BYTE*[nDim1];

	for(int i = 0; i < nDim1; i++)
	{
		ppImg[i] = new BYTE[nDim2];
	}

	return ppImg;
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CFaceFinder::CFaceFinder()
{
	m_CurModelPath = "";
	m_bMirrorDlg = TRUE;

	NULL_POINTER(m_ItgImageX);
	NULL_POINTER(m_ItgImageXX);
	NULL_POINTER(m_pModel);
	NULL_POINTER(m_ppGrayImg);

	float flR = 0;
	float flG = 0;
	float flB = 0;

	float fFiR = 0, fFiG = 0, fFiB = 0;
	float fUR = 0,  fUG = 0,  fUB = 0;
	float fVR = 0,  fVG = 0,  fVB = 0;
 
	for (int i = 0; i < 256; i ++) 
    {
        m_rgbRToY[i]   = flR;
        m_rgbGToY[i]   = flG;
        m_rgbBToY[i]   = flB;

        flR += (float)0.299;
        flG += (float)0.587;
        flB += (float)0.114;

		m_rgbRToFI[i] = fFiR;    
		m_rgbGToFI[i] = fFiG;
		m_rgbBToFI[i] = fFiB;

		fFiR += (float)0.596;
		fFiG += (float)-0.274;
		fFiB += (float)-0.322;

		m_rgbRToU[i] = fUR;    
		m_rgbGToU[i] = fUG;
		m_rgbBToU[i] = fUB;

		fUR += (float)-0.147;
		fUG += (float)-0.289;
		fUB += (float)0.436;

		m_rgbRToV[i] = fVR;    
		m_rgbGToV[i] = fVG;
		m_rgbBToV[i] = fVB;

		fVR += (float)0.615;
		fVG += (float)-0.515;
		fVB += (float)-0.100;

		m_XXTable[i] = i*i;
    }

	m_nMaxLayerNum   = 6000;
	m_nMaxFeatureNum = 80000;

	m_nHeight = 0;
	m_nWidth  = 0;

	m_bConfidence   = FALSE;
//	m_nStdImageSize = 200;    // 20
	m_nStdImageSize = 50;    // 150
//	m_nMaxScaleNum  = 20;    //20
	m_nMaxScaleNum  = 20;    //20
	m_nStep = 1;
	
	m_bMerge = TRUE;//FALSE;
	m_bColor = FALSE;

	m_dbStartscale    = 1.2;//1.2
	m_OriStdImageSize = 0;
//	m_ScaleSize       = 1.2;//1.1
	m_ScaleSize       = 1.2;

	m_ppFiImg  = NULL;
	m_ppFaiImg = NULL;

	m_fRatio = 1.0f;
	//for smodel
	for(int i =0 ; i <m_nSModelNum  ;i ++)
	{
		m_SModelArr[i].FeatureNum = 0;
		m_SModelArr[i].w = NULL;
		m_SModelArr[i].pFeature = NULL;
		m_SModelArr[i].finaltype = NULL;
		m_SModelArr[i].featurescale = NULL;
	}
	m_bSModel = FALSE;
	m_nSModelLayer = 7;
	m_nSModelNum = 0;
	m_bPCA = FALSE;
	m_nModel = 10;

	for(int i=0; i< m_nModel ;i++)
		m_pArrModel[i]= NULL;

	m_bMirror = TRUE;
	m_bAllLayer = FALSE;

	m_nAbsFea = 0;
	m_nMethodThr = 3;
	m_fRatio = 1.0;
	m_bUse4Layer = TRUE;
}

CFaceFinder::~CFaceFinder()
{
	SAFE_RELEASE2(m_ItgImageX,  m_nWidth+1);
	SAFE_RELEASE2(m_ItgImageXX, m_nWidth+1);
	SAFE_RELEASE3(m_ppGrayImg,  m_nWidth);
	SAFE_RELEASE_MODEL(m_pModel);
	for(int i = 0; i < m_nModel; i++)
		SAFE_RELEASE_MODEL(m_pArrModel[i]);
//	m_pArrModel = NULL;
}

void CFaceFinder::SAFE_RELEASE_MODEL(Model* pModel)
{
	if(pModel != NULL)
	{
		SAFE_RELEASE(pModel->finalthreshold);				
		SAFE_RELEASE(pModel->cascade);
		SAFE_RELEASE(pModel->finalh);
		SAFE_RELEASE(pModel->finalsign);
		SAFE_RELEASE(pModel->errorset);
		SAFE_RELEASE(pModel->featureset);	
		SAFE_RELEASE(pModel->apha);

		// potential memory leak...
		delete []pModel->finaltype;
		delete []pModel->featurescale;
		pModel->finaltype    = NULL;
		pModel->featurescale = NULL; 

		delete pModel;
		pModel = NULL;
	}

	m_OriStdImageSize = 0;
}
BOOL DebugInfo1(const char* pDebugInfo)
{
	DWORD BeWrite=0;
	HANDLE hFile;
	hFile=CreateFile("c:\\Detection.txt",GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,NULL);
	if(hFile==INVALID_HANDLE_VALUE)		
		return 0;
	SetFilePointer(hFile,0,0,FILE_END);
	WriteFile(hFile,pDebugInfo,strlen(pDebugInfo),&BeWrite,NULL);
	WriteFile(hFile,"\r\n",2,&BeWrite,NULL);
	CloseHandle(hFile);
	return 1;
}
//load multi-model
BOOL CFaceFinder::LoadModelFromFile(CString szModelFileName[])
{
	if(0)
	{
		//m_nModel = 3;
		m_nModel = 2;

		CString szModelFileName1[10];

		FILE *fp;
		char temp[100];

		CString strModuleFile;
		CString strIniFile;
		char pModuleName[256];
		::GetModuleFileName(g_hModule,pModuleName,256);
		CString strTemp;
		strTemp=pModuleName;
		int pos=strTemp.ReverseFind('\\');
		strModuleFile=strTemp.Left(pos);
		strIniFile=strModuleFile+"\\FaceModel.ini";


		fp = fopen((LPCTSTR)strIniFile, "r");
	//	DebugInfo1(strIniFile);
		fscanf(fp, "%d",&m_nModel);
		int k;
		for(int i = 0; i < m_nModel ; i++)
		{
			fscanf(fp, "%s ", temp);
			szModelFileName1[i] = temp;
			fscanf(fp, "%d", &k);
	//		DebugInfo1(strModuleFile+"\\"+szModelFileName1[i]);
			BOOL b = LoadOneModelFromFile(&m_pArrModel[i], strModuleFile+"\\"+szModelFileName1[i]); 
			if(!b)
				return b;
			m_pArrModel[i]->abs = k;
			m_fThr[i] = m_pArrModel[i]->finalthreshold[m_pArrModel[i]->m_nMaxLayNum];
		}
		szModelFileName1[0] = "FaceFinder-B.MDL";
		szModelFileName1[1] = "FaceFinder-A.MDL";
	}
	else
	{
		m_nModel = 1;
		BOOL b = LoadOneModelFromResource(&m_pArrModel[0]); 
	//	BOOL b = LoadOneModelFromFile(&m_pArrModel[0],"c:\\FaceFinder-7-zl.MDL"); 
		if(!b)
			return b;
		m_pArrModel[0]->abs = 0;
		m_fThr[0] = m_pArrModel[0]->finalthreshold[m_pArrModel[0]->m_nMaxLayNum];
	}

	return TRUE;
}

//lead one model
BOOL CFaceFinder::LoadOneModelFromFile(Model* *m_ppModel, CString szModelFileName)
{
/*	if(m_CurModelPath == szModelFileName)
		return FALSE;
*/	
	SAFE_RELEASE_MODEL(m_pModel);

	Model* m_pModel = new Model;
	ASSERT(m_pModel);

	TRACE("%s\n", m_CurModelPath);
	
	int m_nMaxLayerNum = 9000;
	int m_nMaxFeatureNum = 10000;

	m_pModel->m_nMaxLayNum = m_nMaxLayerNum;
	m_pModel->maxT         = m_nMaxFeatureNum;

	// Allocate memory...

	if(NULL==(m_pModel->cascade=new int[m_nMaxLayerNum+1]))
		return FALSE;
	if(NULL==(m_pModel->finalthreshold=new double[m_nMaxLayerNum+1]))
		return FALSE;
	if(NULL==(m_pModel->finaltype=new int[m_nMaxFeatureNum][6]))
		return FALSE;
	if(NULL==(m_pModel->finalh=new double[m_nMaxFeatureNum]))
		return FALSE;
	if(NULL==(m_pModel->finalsign=new int[m_nMaxFeatureNum]))
		return FALSE;
	if(NULL==(m_pModel->errorset=new double[m_nMaxFeatureNum]))
		return FALSE;
	if(NULL==(m_pModel->featureset=new int[m_nMaxFeatureNum]))
		return FALSE;
	if(NULL==(m_pModel->featurescale=new int[m_nMaxFeatureNum][MAX_SCALE][4]))
		return FALSE;
	if(NULL==(m_pModel->apha=new double[m_nMaxFeatureNum]))
		return FALSE;
	
	// reading model......

	FILE *fpNewModel;
	if( NULL == (fpNewModel = fopen(szModelFileName, "rb")))
		return FALSE;

	fread(&m_pModel->cascade[0],        sizeof(int),    1, fpNewModel);
	fread(&m_pModel->finalthreshold[0], sizeof(double), 1, fpNewModel);
	TrshHold[0] = m_pModel->finalthreshold[0];

	int nLayerNum = 0;
	int count = 0;
	int nByte = 1;

	while(nByte!=0)
	{
		nLayerNum++;
		
		nByte = fread(&m_pModel->cascade[nLayerNum],        sizeof(int),    1, fpNewModel);
		if(nByte <= 0 || nLayerNum == m_nMaxLayerNum+1)
			break;

		nByte = fread(&m_pModel->finalthreshold[nLayerNum], sizeof(double), 1, fpNewModel);
		TrshHold[nLayerNum] = m_pModel->finalthreshold[nLayerNum];

		int nWLNum = m_pModel->cascade[nLayerNum]-m_pModel->cascade[nLayerNum-1];
		m_nFeatureNum  = m_pModel->cascade[nLayerNum];
		for(int i = 0; i < nWLNum; i++)
		{
			nByte = fread(&m_pModel->featureset[count],      sizeof(int),    1, fpNewModel);
			nByte = fread(&m_pModel->finalh[count],          sizeof(double), 1, fpNewModel); 
			nByte = fread(&m_pModel->finalsign[count],       sizeof(int),    1, fpNewModel);
			nByte = fread(&m_pModel->errorset[count],        sizeof(double), 1, fpNewModel);
			nByte = fread(m_pModel->finaltype[count],        sizeof(int),    6, fpNewModel);

	    	count++;
		}
	}

	CFaceFinder::m_nMaxLayerNum = nLayerNum - 1;
	m_pModel->m_nMaxLayNum = nLayerNum - 1;
	m_pModel->maxT = count;
	m_nMaxFeatureNum=m_pModel->cascade[nLayerNum-1];
/*
	CString str;
	str.Format("m_nMaxFeatureNum=%d",m_nMaxFeatureNum);
	DebugInfo1(str);
*/
	
	for (int t=0;t<m_nMaxFeatureNum; t++)
	{
		try
		{
			m_pModel->apha[t]=log((1-m_pModel->errorset[t])/m_pModel->errorset[t]);
		//	str.Format("%f",m_pModel->errorset[t]);
		//	DebugInfo1(str);
		}
		catch(...)
		{
		}
	}

	fclose(fpNewModel);

	float hvalue=0;							
	int tTh, hTh, layer=1;
	do
	{
		int t=m_pModel->cascade[layer-1];
		tTh=m_pModel->cascade[layer];
		hTh=m_pModel->finalthreshold[layer];
		
		while ((t<tTh))
		{
			hvalue+=m_pModel->apha[t];
			t++;
		}
		m_fConfThr[layer-1] = hvalue;
		layer = layer +1;
	}while(layer <= CFaceFinder::m_nMaxLayerNum);

	m_CurModelPath = szModelFileName;
	*m_ppModel = m_pModel;

	return TRUE;
/*	m_nPCAModel = 0;
	PCA.LoadSubSpace(_T("FaceIcons-OR=10-IR=20-108509.eigenspace")); //pca model108509.eigenspace
	
	LoadPCAModel("PCABoostResult1.txt");
	for(int i =0; i< m_nPCAModel; i++)
	{
//		LoadPCAModel(m_PCAModelArr[i], "PCABoostResult.txt"); //F:\\Users\\szli\\Prog\\Detection\\ImageDetection\\  
	}
	
	return LoadSModel("BO_result-10-28.bin");
*/		  
//	return LoadSModel("BO_result.bin");
//	return LoadSModel("BO_result-10000.bin");
//	return TRUE;
}
LPVOID LoadDataResource(WORD resourceID,const char *name)
{
	HMODULE ghmodule=GetModuleHandle(name);
	if(ghmodule==NULL)
	{
		AfxMessageBox("GetModuleHandle fail");
		return NULL;
	}
	else
	{
	//	 AfxMessageBox(name);
	}
	HRSRC hr=FindResource(ghmodule,MAKEINTRESOURCE(resourceID),"MODEL");
	if(hr==NULL)
	{
		int error=GetLastError();
		CString str;
		str.Format("error=%d",error);
		AfxMessageBox(str);
		return FALSE;
	}
	HGLOBAL hg=LoadResource(ghmodule,hr);
	if(hg==NULL)
	{
		FreeResource(hr);
		return FALSE;
	}
	LPVOID pv=(PSZ)LockResource(hg);
	return pv;

}
/*
LPVOID LoadDataResource(LPCTSTR lpResName,const char *name)
{
	HMODULE ghmodule=GetModuleHandle(name);
	if(ghmodule==NULL)
	{
		AfxMessageBox("GetModuleHandle fail");
		return NULL;
	}
	else
	{
	//	 AfxMessageBox(name);
	}
	HRSRC hr=FindResource(ghmodule,lpResName,"MODEL");
	if(hr==NULL)
	{
		int error=GetLastError();
		CString str;
		str.Format("error=%d",error);
		AfxMessageBox(str);
		return FALSE;
	}
	HGLOBAL hg=LoadResource(ghmodule,hr);
	if(hg==NULL)
	{
		FreeResource(hr);
		return FALSE;
	}
	LPVOID pv=(PSZ)LockResource(hg);
	return pv;

}
*/
BOOL CFaceFinder::LoadOneModelFromResource(Model **m_ppModel)
{
	SAFE_RELEASE_MODEL(m_pModel);

	Model* m_pModel = new Model;
	ASSERT(m_pModel);

	TRACE("%s\n", m_CurModelPath);
	
	int m_nMaxLayerNum = 9000;
	int m_nMaxFeatureNum = 10000;

	m_pModel->m_nMaxLayNum = m_nMaxLayerNum;
	m_pModel->maxT         = m_nMaxFeatureNum;

	// Allocate memory...

	if(NULL==(m_pModel->cascade=new int[m_nMaxLayerNum+1]))
		return FALSE;
	if(NULL==(m_pModel->finalthreshold=new double[m_nMaxLayerNum+1]))
		return FALSE;
	if(NULL==(m_pModel->finaltype=new int[m_nMaxFeatureNum][6]))
		return FALSE;
	if(NULL==(m_pModel->finalh=new double[m_nMaxFeatureNum]))
		return FALSE;
	if(NULL==(m_pModel->finalsign=new int[m_nMaxFeatureNum]))
		return FALSE;
	if(NULL==(m_pModel->errorset=new double[m_nMaxFeatureNum]))
		return FALSE;
	if(NULL==(m_pModel->featureset=new int[m_nMaxFeatureNum]))
		return FALSE;
	if(NULL==(m_pModel->featurescale=new int[m_nMaxFeatureNum][MAX_SCALE][4]))
		return FALSE;
	if(NULL==(m_pModel->apha=new double[m_nMaxFeatureNum]))
		return FALSE;
	
	// reading model......
	char pModuleName[256];
	::GetModuleFileName(g_hModule,pModuleName,256);

	LPVOID pv_Feature=LoadDataResource("IDR_FACE_MODEL1",pModuleName);

	if(pv_Feature)
	{
	//	AfxMessageBox(pModuleName);
	}
	else
	{
		AfxMessageBox("Load FaceModal error!");
		return FALSE;
	}

	const char *fpNewModel = (const char *)pv_Feature;

 //   int dl;
	const char *pTemp = fpNewModel;
//	sscanf(&m_pModel->cascade[0],        sizeof(int),    1, fpNewModel);
	const int *p_int = (int *) pTemp;
	m_pModel->cascade[0] = *p_int;
	pTemp += sizeof(int);

//	fread(&m_pModel->finalthreshold[0], sizeof(double), 1, fpNewModel);
	const double *p_double = (double *) pTemp;
	m_pModel->finalthreshold[0] = *p_double;
	pTemp += sizeof(double);

	TrshHold[0] = m_pModel->finalthreshold[0];

	int nLayerNum = 0;
	int count = 0;
	int nByte = 1;

	char* pv_LayerNum=(char*)LoadDataResource("IDR_FACE_MODEL_LAYER",pModuleName);
	int nLayer=0;
	sscanf(pv_LayerNum,"%d",&nLayer);
	/*
	AfxMessageBox(pv_LayerNum);
	CString str;
	str.Format("%d",nLayer);
	AfxMessageBox(str);
	*/

	for(int ii=1;ii<=nLayer;ii++)//7 layer
	{
		nLayerNum++;
		
//		nByte = fread(&m_pModel->cascade[nLayerNum],        sizeof(int),    1, fpNewModel);
		p_int = (int *) pTemp;
		m_pModel->cascade[nLayerNum] = *p_int;
		pTemp += sizeof(int);	
		nByte = sizeof(int);

		if(nByte <= 0 || nLayerNum == m_nMaxLayerNum+1)
			break;

//		nByte = fread(&m_pModel->finalthreshold[nLayerNum], sizeof(double), 1, fpNewModel);
		p_double = (double *) pTemp;
		m_pModel->finalthreshold[nLayerNum] = *p_double;
		pTemp += sizeof(double);

		TrshHold[nLayerNum] = m_pModel->finalthreshold[nLayerNum];

		int nWLNum = m_pModel->cascade[nLayerNum]-m_pModel->cascade[nLayerNum-1];
		m_nFeatureNum  = m_pModel->cascade[nLayerNum];
		for(int i = 0; i < nWLNum; i++)
		{
//			nByte = fread(&m_pModel->featureset[count],      sizeof(int),    1, fpNewModel);
			p_int = (int *) pTemp;
			m_pModel->featureset[count] = *p_int;
			pTemp += sizeof(int);
			
//			nByte = fread(&m_pModel->finalh[count],          sizeof(double), 1, fpNewModel); 
			p_double = (double *) pTemp;
			m_pModel->finalh[count] = *p_double;
			pTemp += sizeof(double);
			
//			nByte = fread(&m_pModel->finalsign[count],       sizeof(int),    1, fpNewModel);
			p_int = (int *) pTemp;
			m_pModel->finalsign[count] = *p_int;
			pTemp += sizeof(int);
			
//			nByte = fread(&m_pModel->errorset[count],        sizeof(double), 1, fpNewModel);
			p_double = (double *) pTemp;
			m_pModel->errorset[count] = *p_double;
			pTemp += sizeof(double);
			
//			nByte = fread(m_pModel->finaltype[count],        sizeof(int),    6, fpNewModel);
			p_int = (int *) pTemp;
			m_pModel->finaltype[count][0] = *p_int;
			pTemp += sizeof(int);

			p_int = (int *) pTemp;
			m_pModel->finaltype[count][1] = *p_int;
			pTemp += sizeof(int);

			p_int = (int *) pTemp;
			m_pModel->finaltype[count][2] = *p_int;
			pTemp += sizeof(int);

			p_int = (int *) pTemp;
			m_pModel->finaltype[count][3] = *p_int;
			pTemp += sizeof(int);

			p_int = (int *) pTemp;
			m_pModel->finaltype[count][4] = *p_int;
			pTemp += sizeof(int);

			p_int = (int *) pTemp;
			m_pModel->finaltype[count][5] = *p_int;
			pTemp += sizeof(int);

	    	count++;
		}
	}

	nLayerNum++;

	CFaceFinder::m_nMaxLayerNum = nLayerNum - 1;
	m_pModel->m_nMaxLayNum = nLayerNum - 1;
	m_pModel->maxT = count;
	m_nMaxFeatureNum=m_pModel->cascade[nLayerNum-1];
	for (int t=0;t<m_nMaxFeatureNum; t++)
		m_pModel->apha[t]=log((1-m_pModel->errorset[t])/m_pModel->errorset[t]);
//	fclose(fpNewModel);

	/*
	FILE *fpNewModel;
	if( NULL == (fpNewModel = fopen(szModelFileName, "rb")))
		return FALSE;

	fread(&m_pModel->cascade[0],        sizeof(int),    1, fpNewModel);
	fread(&m_pModel->finalthreshold[0], sizeof(double), 1, fpNewModel);
	TrshHold[0] = m_pModel->finalthreshold[0];

	int nLayerNum = 0;
	int count = 0;
	int nByte = 1;

	while(nByte!=0)
	{
		nLayerNum++;
		
		nByte = fread(&m_pModel->cascade[nLayerNum],        sizeof(int),    1, fpNewModel);
		if(nByte <= 0 || nLayerNum == m_nMaxLayerNum+1)
			break;

		nByte = fread(&m_pModel->finalthreshold[nLayerNum], sizeof(double), 1, fpNewModel);
		TrshHold[nLayerNum] = m_pModel->finalthreshold[nLayerNum];

		int nWLNum = m_pModel->cascade[nLayerNum]-m_pModel->cascade[nLayerNum-1];
		m_nFeatureNum  = m_pModel->cascade[nLayerNum];
		for(int i = 0; i < nWLNum; i++)
		{
			nByte = fread(&m_pModel->featureset[count],      sizeof(int),    1, fpNewModel);
			nByte = fread(&m_pModel->finalh[count],          sizeof(double), 1, fpNewModel); 
			nByte = fread(&m_pModel->finalsign[count],       sizeof(int),    1, fpNewModel);
			nByte = fread(&m_pModel->errorset[count],        sizeof(double), 1, fpNewModel);
			nByte = fread(m_pModel->finaltype[count],        sizeof(int),    6, fpNewModel);

	    	count++;
		}
	}

	CFaceFinder::m_nMaxLayerNum = nLayerNum - 1;
	m_pModel->m_nMaxLayNum = nLayerNum - 1;
	m_pModel->maxT = count;
	for (int t=0;t<m_nMaxFeatureNum; t++)
		m_pModel->apha[t]=log((1-m_pModel->errorset[t])/m_pModel->errorset[t]);
	fclose(fpNewModel);
*/

	float hvalue=0;							
	int tTh, hTh, layer=1;
	do
	{
		int t=m_pModel->cascade[layer-1];
		tTh=m_pModel->cascade[layer];
		hTh=m_pModel->finalthreshold[layer];
		
		while ((t<tTh))
		{
			hvalue+=m_pModel->apha[t];
			t++;
		}
		m_fConfThr[layer-1] = hvalue;
		layer = layer +1;
	}while(layer <= CFaceFinder::m_nMaxLayerNum);

	
//	m_CurModelPath = szModelFileName;
	*m_ppModel = m_pModel;
	return TRUE;
}

inline void CFaceFinder::GetItgImage(BYTE** pImage, int ImageWidth, int ImageHeight)
{
	int x, y;

	for( x=0; x<ImageWidth+1; x++) 
	{
		memset(m_ItgImageX[x],  0, sizeof(int)*(ImageHeight+1));
		memset(m_ItgImageXX[x], 0, sizeof(int)*(ImageHeight+1));
	}
	
	int* s  = new int[ImageHeight];
	int* ss = new int[ImageHeight];

	for( x=0; x<ImageWidth; x++)
	{
		for( y=0; y<ImageHeight; y++)
		{
			if (y!=0)
			{
				s[y]  = s[y-1] +pImage[x][y];    
			//	ss[y] = ss[y-1]+pImage[x][y]*pImage[x][y];    
				ss[y] = ss[y-1]+m_XXTable[pImage[x][y]];
			}
			else  
			{
				 s[y] = pImage[x][y];
			//	ss[y] = pImage[x][y]*pImage[x][y];
				ss[y] = m_XXTable[pImage[x][y]];
			}

			 m_ItgImageX[x+1][y+1]  =  m_ItgImageX[x][y+1]+s[y];		
			 m_ItgImageXX[x+1][y+1] = m_ItgImageXX[x][y+1]+ss[y];		
		}
	}

	SAFE_RELEASE(s);
	SAFE_RELEASE(ss);
}

inline double CFaceFinder::GetVariance(int scalenum, int x, int y, int winm, int winn)
{
	__int64 s1,s2;

	s1 = m_ItgImageX[x+winm][y+winn]
	   + m_ItgImageX[x][y]
	   - m_ItgImageX[x+winm][y]
	   - m_ItgImageX[x][y+winn];

	s2 = m_ItgImageXX[x+winm][y+winn]
	   + m_ItgImageXX[x][y]
	   - m_ItgImageXX[x+winm][y]
	   - m_ItgImageXX[x][y+winn];

/*	
	double dbTmp = m_nWindowArea[scalenum]*m_nWindowArea[scalenum];
	if(dbTmp != 0)
		dbVariance = (s2*m_nWindowArea[scalenum]-s1*s1)/dbTmp;
	else
		dbVariance = 1; 
*/

	
	// ATTENTION: dbTmp is out of range !!
/*
	double dbTmp = m_nWindowArea[scalenum]*m_nWindowArea[scalenum];
	ASSERT(dbTmp!=0);
*/

//	int dbVariance = ((int)(s2 - (s1/m_nWindowArea[scalenum])*s1))/m_nWindowArea[scalenum];
	int dbVariance = ((int)(s2 - s1*s1/m_nWindowArea[scalenum]))/m_nWindowArea[scalenum];

	if(dbVariance<0)
	{
		int k;
		k=0;
	}
	
	if (dbVariance==0) 
		dbVariance=1;	

	return dbVariance;
} 

inline int CFaceFinder::GetFeatureValue(int **itgimage, int type, int* pos, int PosX, int PosY, const int ScaleNo)
{
	if(m_bMirrorDlg)
	{
		int m, n;
		n = m_nWindowSize[ScaleNo];
		m = n >> 1;
		
		if(GetFeatureValue(itgimage, 1, m, n, PosX, PosY) < 0)
		{
			int pos2 = pos[2];
			switch(type)
			{
			case 1:
			case 4:
			case 5:
			case 6:
				pos2 = n - pos[2] - pos[0]*2;
				break;
			case 2:
				pos2 = n - pos[2] - pos[0];
				break;
			case 3:
				pos2 = n - pos[2] - pos[0]*3;
				break;
			}
			
			return MirSign[type] * GetFeatureValue(itgimage, MirType[type], pos[0], pos[1], pos2 + PosX, pos[3] + PosY);
		}
	}
	return GetFeatureValue(itgimage, type, pos[0], pos[1], pos[2] + PosX, pos[3] + PosY);
}

inline int CFaceFinder::GetFeatureValue(int **itgimage, int type, int mm, int nn, int x, int y)
{	
//	double s1,s2,s3,s4,ss;
 
	int s2 = 0;
	switch (type)
		{
		case 1:
            //s1=itgimage[x+mm][y+nn]+itgimage[x][y]-itgimage[x+mm][y]-itgimage[x][y+nn];
            //s2=itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn];
            //ss = (s2 - s1);
//			return itgimage[x+mm+mm][y+nn]+(itgimage[x+mm][y] << 1)-itgimage[x+mm+mm][y]-(itgimage[x+mm][y+nn] << 1)
//				   -itgimage[x][y]+itgimage[x][y+nn];
			s2 = itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn]
				   - itgimage[x+mm][y+nn]-itgimage[x][y]+itgimage[x+mm][y]+itgimage[x][y+nn];
			break;
        case 2:
            //s1=itgimage[x+mm][y+nn]+itgimage[x][y]-itgimage[x+mm][y]-itgimage[x][y+nn];
            //s2=itgimage[x+mm][y+nn+nn]+itgimage[x][y+nn]-itgimage[x][y+nn+nn]-itgimage[x+mm][y+nn];
            //ss=(s1-s2);
			//return (itgimage[x+mm][y+nn] << 1)+itgimage[x][y]-itgimage[x+mm][y]-(itgimage[x][y+nn] << 1)
			// - itgimage[x+mm][y+nn+nn]+itgimage[x][y+nn+nn];
			s2 = itgimage[x+mm][y+nn]+itgimage[x][y]-itgimage[x+mm][y]-itgimage[x][y+nn]
				   - itgimage[x+mm][y+nn+nn]-itgimage[x][y+nn]+itgimage[x][y+nn+nn]+itgimage[x+mm][y+nn];
			break;
        case 3:
            //s1=itgimage[x+mm][y+nn]+itgimage[x][y]-itgimage[x+mm][y]-itgimage[x][y+nn];
            //s2=itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn];
            //s3=itgimage[x+mm+mm+mm][y+nn]+itgimage[x+mm+mm][y]-itgimage[x+mm+mm+mm][y]-itgimage[x+mm+mm][y+nn];
            //ss=(s2+s2-s1-s3);
//			s2=itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn];
			//	   + itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn];
//			return (s2 << 1) - itgimage[x+mm][y+nn]-itgimage[x][y]+itgimage[x+mm][y]+itgimage[x][y+nn]
//				   - itgimage[x+mm+mm+mm][y+nn]-itgimage[x+mm+mm][y]+itgimage[x+mm+mm+mm][y]+itgimage[x+mm+mm][y+nn];
			s2 = itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn]
				   + itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn]
				   - itgimage[x+mm][y+nn]-itgimage[x][y]+itgimage[x+mm][y]+itgimage[x][y+nn]
				   - itgimage[x+mm+mm+mm][y+nn]-itgimage[x+mm+mm][y]+itgimage[x+mm+mm+mm][y]+itgimage[x+mm+mm][y+nn];
			break;
        case 4:                   
            //s1=itgimage[x+mm][y+nn]+itgimage[x][y]-itgimage[x+mm][y]-itgimage[x][y+nn];
            //s2=itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn];
            //s3=itgimage[x+mm][y+nn+nn]+itgimage[x][y+nn]-itgimage[x][y+nn+nn]-itgimage[x+mm][y+nn];
            //s4=itgimage[x+mm+mm][y+nn+nn]+itgimage[x+mm][y+nn]-itgimage[x+mm+mm][y+nn]-itgimage[x+mm][y+nn+nn];
            //ss=(s2+s3-s1-s4);                    
//			return (itgimage[x+mm+mm][y+nn] << 1)+(itgimage[x+mm][y] << 1)-itgimage[x+mm+mm][y]-(itgimage[x+mm][y+nn] << 2)
//				   + (itgimage[x+mm][y+nn+nn] << 1)+(itgimage[x][y+nn] << 1) -itgimage[x][y+nn+nn]
//				   -itgimage[x][y] - itgimage[x+mm+mm][y+nn+nn];
			s2 = itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn]
				   + itgimage[x+mm][y+nn+nn]+itgimage[x][y+nn]-itgimage[x][y+nn+nn]-itgimage[x+mm][y+nn]
				   - itgimage[x+mm][y+nn]-itgimage[x][y]+itgimage[x+mm][y]+itgimage[x][y+nn]
				   - itgimage[x+mm+mm][y+nn+nn]-itgimage[x+mm][y+nn]+itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y+nn+nn];
			break;
		case 5:                   
            //s1=itgimage[x+mm][y+nn]+itgimage[x][y]-itgimage[x+mm][y]-itgimage[x][y+nn];
            //s4=itgimage[x+mm+mm][y+nn+nn]+itgimage[x+mm][y+nn]-itgimage[x+mm+mm][y+nn]-itgimage[x+mm][y+nn+nn];
            //ss=(s1-s4);                    
//			return itgimage[x][y]-itgimage[x+mm][y]-itgimage[x][y+nn]
//				   - itgimage[x+mm+mm][y+nn+nn]+itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y+nn+nn];
			s2 = itgimage[x+mm][y+nn]+itgimage[x][y]-itgimage[x+mm][y]-itgimage[x][y+nn]
				   - itgimage[x+mm+mm][y+nn+nn]-itgimage[x+mm][y+nn]+itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y+nn+nn];
			break;
		case 6:                   
            //s2=itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn];
            //s3=itgimage[x+mm][y+nn+nn]+itgimage[x][y+nn]-itgimage[x][y+nn+nn]-itgimage[x+mm][y+nn];
            //ss=(s2-s3);                    
//			return itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]
//				   - itgimage[x+mm][y+nn+nn]-itgimage[x][y+nn]+itgimage[x][y+nn+nn];
			s2 = itgimage[x+mm+mm][y+nn]+itgimage[x+mm][y]-itgimage[x+mm+mm][y]-itgimage[x+mm][y+nn]
				   - itgimage[x+mm][y+nn+nn]-itgimage[x][y+nn]+itgimage[x][y+nn+nn]+itgimage[x+mm][y+nn];
			break;

		case 7:
			{
				float H,V;
				float result;
				H=CalSobel(x,y,mm,nn,hSobel_Template,itgimage);
				V=CalSobel(x,y,mm,nn,vSobel_Template,itgimage);

				result=sqrt(H*H+V*V);
                /*
				result=(result/1442.28)*360;//1442.28=4*255*1.414 the max value of sobel filter
				if(result>360)
					result=360;	
				*/
				s2=result;
			}
			break;
		case 8:
			{
				float H,V;
				float result;
				H=CalSobel(x,y,mm,nn,hSobel_Template,itgimage);
				V=CalSobel(x,y,mm,nn,vSobel_Template,itgimage);

				if(H==0.0F&&V<=0.0F)
					result=((-0.5)*3.1415926);
				else if(H==0.0F&&V>0.0F)
					result=(0.5*3.1415926);
				else
					result=atan(V/H);

				result=(result/3.1415926)*360+180;				
				s2=result;
			}
		case 9:
			s2=itgimage[x+mm][y+nn]-itgimage[x][y];
			break;
	}
	if(m_nAbsFea == 0)
		return s2;
	else
		return abs(s2);	
		
	
}

bool CFaceFinder::IsFace_Cascade(const int PosX, const int PosY,const int ScaleNo, float& dbConfidence, float *pfConfidence)
{
	int WindowSize = m_nWindowSize[ScaleNo];
	int layer, t, tTh;
	double variance_scale, hTh, hvalue;

	double dbVariance = GetVariance(ScaleNo, PosX, PosY, WindowSize, WindowSize);

	int * pTmp;

	if (dbVariance > MIN_STD_VARIANCE)
	{
		dbVariance     = sqrt(dbVariance);
		variance_scale = dbVariance*m_dbScaleArea[ScaleNo];

		layer=1;

//		hvalue=0;							
		do
		{
			t=m_pModel->cascade[layer-1];
			tTh=m_pModel->cascade[layer];
			hTh=m_pModel->finalthreshold[layer];

			hvalue=0;
		

			while ((t<tTh))// && (hvalue<hTh))
			{
				pTmp = m_pModel->featurescale[t][ScaleNo];

				if((m_pModel->finalh[t]*variance_scale > 
					GetFeatureValue(m_ItgImageX, 
					                m_pModel->finaltype[t][1],
									pTmp[0],
									pTmp[1],
									pTmp[2]+PosX,
									pTmp[3]+PosY)) != (m_pModel->finalsign[t]>0))
					hvalue += m_pModel->apha[t];
				
				t++;
			}	

			if (hvalue<hTh) 
				return false;

			layer++;
		}while( (layer <= m_nMaxLayerNum));


		dbConfidence = hvalue /m_fConfThr[layer-2];
		// added PCA method 

		return true;		
	
	}
	
	return false;
}

bool CFaceFinder::IsFace(const int PosX, const int PosY,const int ScaleNo, float& dbConfidence, float *pfConfidence)
{
	int WindowSize = m_nWindowSize[ScaleNo];
	int layer, t, tTh;
	double variance_scale, hTh, hvalue;

	double dbVariance = GetVariance(ScaleNo, PosX, PosY, WindowSize, WindowSize);

	int * pTmp;

//	if (dbVariance > MIN_STD_VARIANCE)
	{
		dbVariance     = sqrt(dbVariance);
		variance_scale = dbVariance*m_dbScaleArea[ScaleNo];

		layer=1;

		hvalue=0;							
		do
		{
			t=m_pModel->cascade[layer-1];
			tTh=m_pModel->cascade[layer];
			hTh=m_pModel->finalthreshold[layer];
		
			while ((t<tTh))// && (hvalue<hTh))
			{
				pTmp = m_pModel->featurescale[t][ScaleNo];

				if((m_pModel->finalh[t]*variance_scale > 
					GetFeatureValue(m_ItgImageX, 
					                m_pModel->finaltype[t][1],
									pTmp[0],
									pTmp[1],
									pTmp[2]+PosX,
									pTmp[3]+PosY)) != (m_pModel->finalsign[t]>0))
					hvalue += m_pModel->apha[t];
				
				t++;
			}	
//			pfConfidence[layer-1] = hvalue / m_fConfThr[layer-1];
//			pfConfidence[layer-1] = hvalue / (2*m_pModel->finalthreshold[layer]);m_pModel->m_nMaxLayNum
			layer++;
//		}while((layer <= m_nMaxLayerNum));
		}while((layer>10 || hvalue>=m_pModel->finalthreshold[layer-1]) && (layer <= m_pModel->m_nMaxLayNum));//m_nMaxLayerNum));//=m_pModel->m_nMaxLayNum));

		if (hvalue>=m_pModel->finalthreshold[layer-1])
		{
/*			if(layer <= m_pModel->m_nMaxLayNum)
			{
				t=m_pModel->cascade[layer-1];
				tTh=m_pModel->cascade[layer];
				hTh=m_pModel->finalthreshold[layer];
				while (t<tTh)
				{
					pTmp = m_pModel->featurescale[t][ScaleNo];

					if((m_pModel->finalh[t]*variance_scale > 
						GetFeatureValue(m_ItgImageX, 
										m_pModel->finaltype[t][1],
										pTmp[0],
										pTmp[1],
										pTmp[2]+PosX,
										pTmp[3]+PosY)) != (m_pModel->finalsign[t]>0))
						hvalue+=m_pModel->apha[t];
					
					t++;
				}		
			}*/
			//
			dbConfidence = hvalue /m_fConfThr[layer-2];
		// added PCA method 

			return true;		
		}
	}
	
	return false;
}

inline double CFaceFinder::PrepareModel(const int StdImageSize)
{
	
	double StartScale = (double)StdImageSize/STDIMAGESIZE;

	static int lastSize=0;
	if(StdImageSize==lastSize) return StartScale;
	lastSize=StdImageSize;

	double scale=StartScale; 
	
	//bulid featurescale for each size

	int i,t;
	for (i=0; i<MAX_SCALE; i++)
	{
		for(int m = 0; m<m_nModel; m++)
		{		
			if(m_pArrModel[m]==NULL)
				continue;
			for (t=0; t<m_pArrModel[m]->maxT; t++)
			{
				m_pArrModel[m]->featurescale[t][i][0] = int(m_pArrModel[m]->finaltype[t][2]*scale);
				m_pArrModel[m]->featurescale[t][i][1] = int(m_pArrModel[m]->finaltype[t][3]*scale);
				m_pArrModel[m]->featurescale[t][i][2] = int((m_pArrModel[m]->finaltype[t][4]-1)*scale);
				m_pArrModel[m]->featurescale[t][i][3] = int((m_pArrModel[m]->finaltype[t][5]-1)*scale);
			}
		}

		// following is for SVM model
		/*		for(int j =0 ; j <m_nSModelNum  ; j ++)
		{
		for (t=0; t<m_SModelArr[j].FeatureNum; t++)
		{
		m_SModelArr[j].featurescale[t][i][0] = int(m_SModelArr[j].finaltype[t][1]*scale);
		m_SModelArr[j].featurescale[t][i][1] = int(m_SModelArr[j].finaltype[t][2]*scale);
		m_SModelArr[j].featurescale[t][i][2] = int(m_SModelArr[j].finaltype[t][3]*scale);//-1
		m_SModelArr[j].featurescale[t][i][3] = int(m_SModelArr[j].finaltype[t][4]*scale);//-1
		}
	}*/	
		m_nWindowSize[i]=int(STDIMAGESIZE*scale);
		m_nWindowArea[i]=m_nWindowSize[i]*m_nWindowSize[i];
		m_dbScaleArea[i]=m_nWindowSize[i]/((double)(StdImageSize))*StartScale;
		m_dbScaleArea[i]=m_dbScaleArea[i]*m_dbScaleArea[i];
		scale=scale*m_ScaleSize;
	}
	return StartScale;
}

Found_Face * CFaceFinder::DoFaceFinder(BYTE **ppImg, const int nWidth, const int nHeight, BOOL bMirror)
{
	m_bMirrorDlg = bMirror;

	for(int nScale = 0; nScale < m_nMaxScaleNum; nScale++)
	{
		m_DetectionRect[nScale].clear();
		m_MergeRect[nScale].clear();
	}

	int px, py, winsize, i, scalenum, MaxSize;

	double step;
	double scale;
	int count;

	if(m_nHeight != nHeight || m_nWidth != nWidth)
	{
		SAFE_RELEASE2(m_ItgImageX,  m_nWidth+1);
		SAFE_RELEASE2(m_ItgImageXX, m_nWidth+1);
		SAFE_RELEASE3(m_ppGrayImg,  m_nWidth);
		if(m_bColor)
		{
			SAFE_RELEASE2(m_ppFiImg , m_nWidth); 
			SAFE_RELEASE2(m_ppFaiImg, m_nWidth); 
		}
		m_nHeight = nHeight;
		m_nWidth  = nWidth;
		
		m_ItgImageX  = New_2D(m_nWidth+1, m_nHeight+1);
		m_ItgImageXX = New_2D(m_nWidth+1, m_nHeight+1);
		m_ppGrayImg  = New_2D2(m_nWidth,  nHeight);

		if(m_bColor)
		{
			m_ppFiImg  = New_2D(m_nWidth, m_nHeight); 
			m_ppFaiImg = New_2D(m_nWidth, m_nHeight);
		}
	}

	MaxSize = MIN(m_nHeight, m_nWidth);

	GetGrayImg(ppImg, nWidth, nHeight);
	if(m_bColor)
		GetFiFaiImg(ppImg, nWidth, nHeight);

	GetItgImage(m_ppGrayImg, nWidth, nHeight);

	// ATTENTION: questions???????????????
	// this part change for start with big face
	//the follwoing part is changed by QiaoYU 2002-10-09
	if(m_nStdImageSize == 0)
		m_nStdImageSize = max(30, MaxSize/30);
//	m_nStdImageSize = max(24, MaxSize*0.04);
/*	if(m_nStdImageSize < 20)
		m_nStdImageSize = 24;
*/
	m_dbStartscale    = PrepareModel(m_nStdImageSize);
	m_OriStdImageSize = m_nStdImageSize;
/*	
	if(m_OriStdImageSize != m_nStdImageSize)
	{
		m_dbStartscale    = PrepareModel(m_nStdImageSize);
		m_OriStdImageSize = m_nStdImageSize;
	}
	*/
//end of change
	scale    = m_dbStartscale;
	step     = STARTSTEP*m_dbStartscale;
	scalenum = 0;

	float dbConfidence = 0.0f;
	float fMultiConf[20];
//	int g_count = 0;

	do
	{				
		winsize = m_nWindowSize[scalenum];			

		px = 0;
		while((px+winsize<m_nWidth+1))
		{
			py = 0;
			while((py+winsize<m_nHeight+1))
			{	
		//		g_count++;GetFaceConf
		//		m_nMaxLayerNum = 7;           // add for svm testing
		//		if(IsFace(px, py, scalenum, dbConfidence, fMultiConf))
				BOOL bRsl;
/*				if(m_bAllLayer)
				{
					bRsl = IsFace1(px, py, scalenum, dbConfidence, m_nSModelLayer);
				}
				else
				{
					bRsl = IsFace2(px, py, scalenum, dbConfidence, m_nSModelLayer);
				}*/
		//		bRsl = IsFaceSubMdl(px, py, scalenum);
				bRsl = IsFace1(px, py, scalenum, dbConfidence, m_nSModelLayer);
				if( bRsl )
		//		if(GetFaceConf(px, py, winsize, dbConfidence, fMultiConf))
				{
		//			GetFaceConf(px, py, winsize, dbConfidence, fMultiConf);
					BOOL bPush = TRUE;
					if(m_bColor)
					{
						bPush = JudgeImage(px, py, winsize, winsize);
					}
/*					if(bPush && m_bPCA)
					{
						CPreproc      PreProc;
						BYTE * pResizeImg = new BYTE[STDIMAGESIZE*STDIMAGESIZE];
						BYTE * img = new BYTE[winsize*winsize];
						float* pVector = new float[STDIMAGESIZE*STDIMAGESIZE];
						float* pFeature = new float[STDIMAGESIZE*STDIMAGESIZE];
						
						for(int i = 0; i< winsize; i++)
						for(int j = 0; j< winsize; j++)
						{
						//	img[(winsize-1-i)*winsize+j] = m_ppGrayImg[px+j][py+i];
							img[i*winsize+j] = m_ppGrayImg[px+j][py+i];
						}

						PreProc.ResizeImage(img,winsize,winsize,pResizeImg,STDIMAGESIZE,STDIMAGESIZE);
						PreProc.StanPreProcessImg(pResizeImg,STDIMAGESIZE,STDIMAGESIZE,pVector);
					//	PreProc.SaveBmpImg("C:\\Test.bmp", pVector, 20, 20);

						PCA.Project2SubSpace(pVector, pFeature, 400);
						
						for(int nnId = 0; nnId < 400; nnId++)
						{
							if(abs(PCA.m_plfEigenVals[nnId])> 0.0000000001)
								pFeature[nnId] = pFeature[nnId]/sqrt(abs(PCA.m_plfEigenVals[nnId]));
						}

						//add code for test it is face or not
						for(i=0; i<m_nPCAModel && bPush; i++)
						{
							bPush = StrongClassify(m_PCAModelArr[i], pFeature);
						}
						//CString fileName;
						//fileName.Format("D:\\SVM-ICON\\%07d.bmp", NUM_IMG);
						//SaveBmpImg(fileName, img, winsize, winsize);
						delete[]  pVector;
						delete[]  pFeature;
						delete[]  img;
						delete[]  pResizeImg;
					}*/
					if(bPush)
					{
						CPosition pos(px,py,1,dbConfidence);					
						for(int i=0; i<m_nMaxLayerNum ;i++)
							pos.MultiConf[i] = fMultiConf[i];
						m_DetectionRect[scalenum].push_back(pos);
						// add pca method 
						// crop images for svm testing
					}					
				}

				py+=int(step)+m_nStep;
				//py+=1;//int(step)+m_nStep;
			}

			px+=int(step)+m_nStep;//1;    
		}

		scale *= m_ScaleSize;
		step  *= m_ScaleSize;
		scalenum++;

	}while ((scalenum<m_nMaxScaleNum)); //MAX_SCALE
//	ReSample();
	BOOL bMergeResult = FALSE;
//UOTPUT_DETECTION_RESULT


	if(m_bMerge)
		bMergeResult = merge();
	
	if(bMergeResult == FALSE || m_bMerge == FALSE)
	{
		for(int nScale = 0; nScale < m_nMaxScaleNum; nScale++)
		{
			m_MergeRect[nScale].clear();
			for(int k = 0; k < m_DetectionRect[nScale].size(); k++)
			m_MergeRect[nScale].push_back(m_DetectionRect[nScale][k]);
		}
	}

	count=0;
	for(i=0;i<m_nMaxScaleNum;i++)
		count += m_MergeRect[i].size();

	Found_Face * pRois = new Found_Face;
	pRois->dwNumROI = count;

//UOTPUT_DETECTION_RESULT
	if(count != 0)
	{
		pRois->rcROI = new RECT[pRois->dwNumROI];
		
		int k = 0;
		std::vector<CPosition>::reverse_iterator itor;
		
		for ( i=0; i<MAX_SCALE; i++) 
		{
			for(itor = m_MergeRect[i].rbegin(); itor != m_MergeRect[i].rend(); itor++)
			{
				pRois->rcROI[k].left    = itor->x;
				pRois->rcROI[k].top     = itor->y;
				pRois->rcROI[k].right   = itor->x + m_nWindowSize[i];
				pRois->rcROI[k].bottom  = itor->y + m_nWindowSize[i];
				k++;
			}
			
			m_MergeRect[i].erase(m_MergeRect[i].begin(), m_MergeRect[i].end());
		}
	}

	return pRois;
}

// suppose there is only one detection model

BOOL CFaceFinder::merge()
{
	int i, ii, count=0;
	// rule1: if there only one or no RECT, so do not merge
	int nSum = 0;
	for (i=m_nMaxScaleNum-1; i>=0; i--)
		nSum += m_DetectionRect[i].size();

	int nMinDetections;

	if(nSum < 2)  
	{
/*		for (i=m_nMaxScaleNum-1; i>=0; i--)
		{
			std::vector<CPosition>::iterator itor;
			for( itor = m_DetectionRect[i].begin(); itor != m_DetectionRect[i].end();itor++ )
			{
				ReSampleAt(itor->x, itor->y, m_nWindowSize[i]);

			}
		}
*/		return FALSE;
	}
	else if(nSum == 2)
		nMinDetections = 1;
	else
		nMinDetections = 2;
	// end rule1

	// rule2: select continue 10 scales from 20 scales 
	int* nSumArray = new int[m_nMaxScaleNum];
	
	for(i = 0; i < m_nMaxScaleNum; i++)
		nSumArray[i] = m_DetectionRect[i].size() * (i+1);

	int nWinSize  = m_nMaxScaleNum/2;
	int nMaxSum   = 0;
	int nMaxBegin = 0;
/*	
	for(int nBegin = 0; nBegin < m_nMaxScaleNum - nWinSize; nBegin++)
	{
		nSum = 0;
		
		for(int nEnd = nBegin; nEnd < nBegin+nWinSize; nEnd++)
			nSum += nSumArray[nEnd];

		if(nMaxSum < nSum)
		{
			nMaxSum = nSum; 
			nMaxBegin = nBegin;
		}
	}

	for (i = m_nMaxScaleNum-1; i > nMaxBegin+nWinSize; i--)
		m_DetectionRect[i].clear();
	for (i = 0; i < nMaxBegin; i++)
		m_DetectionRect[i].clear();
*/
	SAFE_RELEASE(nSumArray);
	// end rule2

	double scale;
	
	//int flag;
	std::vector<CPosition>::iterator itor, itor1;
	
	scale=m_dbStartscale;	
	
	//for each scale
	//we can do the following work
	int nMaxScale = m_nMaxScaleNum;
	int maxdistance = 4;

	BOOL bDetectSame;
	int minx ;
	int maxx ;
	int miny ;
	int maxy ;
	int nSimWin,sumX,sumY;
	int tX, tY;
	float tmpConfd, sumConfd;
	for (i=0; i<nMaxScale; i++)
	{
		//The candidate face window with same size
		for(itor = m_DetectionRect[i].begin(); itor < m_DetectionRect[i].end();itor++ )
		{
			bDetectSame = FALSE;
			minx = itor->x -maxdistance*scale;
			maxx = itor->x +maxdistance*scale;
			miny = itor->y -maxdistance*scale;
			maxy = itor->y +maxdistance*scale;
			nSimWin=1,sumX=itor->x,sumY=itor->y;
			tX=itor->x, tY=itor->y;
			tmpConfd =itor->Confidence;
			sumConfd =itor->Confidence;
			for(itor1 = itor+1; itor1 < m_DetectionRect[i].end(); )
			{
				if ((itor1->x > minx) &&(itor1->x < maxx) && (itor1->y > miny) &&(itor1->y < maxy) )
				{
					nSimWin++;
					if(itor1->x +maxdistance*scale > maxx)
						maxx = itor1->x +maxdistance*scale;
					
					if(itor1->y +maxdistance*scale > maxy)
						maxy = itor1->y +maxdistance*scale;
					sumX+= itor1->x;
					sumY+= itor1->y;
					sumConfd +=itor1->Confidence;
					if(itor1->Confidence > tmpConfd)
					{
						tmpConfd = itor1->Confidence;
						tX = itor1->x, tY = itor1->y;
					}
					m_DetectionRect[i].erase(itor1);
					bDetectSame = TRUE;
				}
				else
					itor1 ++;
			}

			if(bDetectSame)
			{
				//use average as the 
				itor->x = sumX/nSimWin;
				itor->y = sumY/nSimWin;
				itor->DetectionSum = nSimWin;
				//itor->x = tX;
				//itor->y = tY;
				//itor->Confidence=sumConfd /nSimWin ;
				itor->Confidence = tmpConfd;
				//itor->Confidence=sumConfd;
			}
		}
		scale=scale*m_ScaleSize;
	}

	//acumulate the count number in the neighbour scale

	int top,  bottom,  left,  right,  iMin,  iMax,  area;
	int top1, bottom1, left1, right1, area1, area2, area3;
	
	for(i=0; i<nMaxScale; i++)
	{
		for( itor = m_DetectionRect[i].begin(); itor != m_DetectionRect[i].end(); itor++)
		{
			itor->sumConfidence = itor->Confidence ;
		}
	}
	for(i=0; i<nMaxScale; i++)
	{
		for( itor = m_DetectionRect[i].begin(); itor <m_DetectionRect[i].end(); itor++)
		{
			top = itor->y;
			bottom = itor->y+m_nWindowSize[i];
			left = itor->x;
			right = itor->x+m_nWindowSize[i];
			iMin = (i-3 >= 0)? i-3:0;
			iMax = (i+3<nMaxScale)?i+3:nMaxScale-1;
			area = (bottom-top)*(right-left);

			for(ii = iMin; ii <= iMax; ii++)
			{
				for( itor1 = m_DetectionRect[ii].begin(); itor1 <m_DetectionRect[ii].end(); itor1++)
				{
					if(ii!=i || itor!=itor1)
					{
						top1 = itor1->y;
						bottom1 = itor1->y+m_nWindowSize[ii];
						left1 = itor1->x;
						right1 = itor1->x+m_nWindowSize[ii];
						area1 = (bottom1-top1)*(right1-left1);
						area2 = OverlapRect(top,bottom,left,right,top1,bottom1,left1,right1);
						if(area2>area1*1/2 && area2>area*1/2 )
						{
							itor->DetectionSum++;
							itor->sumConfidence += itor1->Confidence;
						}
					}
				}
			}
		}
	}

	//delete the widows with scale number less than nMinDetections
	
	for (i=m_nMaxScaleNum-1; i>=0; i--)
	{
		for( itor = m_DetectionRect[i].begin(); itor != m_DetectionRect[i].end(); )
		{
			if ( itor->DetectionSum < nMinDetections)
			{
//				ReSampleAt(itor->x, itor->y, m_nWindowSize[i]);
				itor = m_DetectionRect[i].erase(itor);
			}
			else
			{
				itor++;
			}
		}
	}

	BOOL bMergeOver = FALSE;
	do 
	{
		bMergeOver = TRUE;
		int maxtemp = -1;
		int ii;
		//find the windows with the largest confidece in all scales 
		//do merge for these scales
		float maxconfidence = 0;
		for (i=nMaxScale-1; i>=0; i--)  //from big size to small size
//		for (i=0; i<nMaxScale; i++)     //from small size to big size
		{
			for( itor = m_DetectionRect[i].begin(); itor != m_DetectionRect[i].end(); itor++)
			{
				//using the confidence
				if(m_bConfidence)
				{
					double ttt=itor->sumConfidence;
					if( itor->sumConfidence > maxconfidence)
					{
						maxconfidence = itor->sumConfidence ;
						ii = i;
						itor1 = itor;
						bMergeOver = FALSE;
					}
				}
				else
				{
					//using count number
					if( itor->DetectionSum>maxtemp )
					{
						maxtemp = itor->DetectionSum;
						ii = i;
						itor1 = itor;
						bMergeOver = FALSE;
						//nnSubmodel=nSubmodel;
					}
				}
			}
		}							
		if (!bMergeOver)
		{
			top=itor1->y;
			bottom=itor1->y+m_nWindowSize[ii];
			left=itor1->x;
			right=itor1->x+m_nWindowSize[ii];
			area1 = (bottom-top)*(right-left);
			for (i=0; i<nMaxScale; i++)
			{
				for (itor = m_DetectionRect[i].begin(); itor < m_DetectionRect[i].end(); )
				{
					if(itor != itor1 || i != ii)
					{
						top1=itor->y;
						bottom1=itor->y+m_nWindowSize[i];
						left1=itor->x;
						right1=itor->x+m_nWindowSize[i];
						area2 = (bottom1-top1)*(right1-left1);
						area3=OverlapRect(top,bottom,left,right,top1,bottom1,left1,right1);
						if(area3>area1*1/4 || area3>area2*1/4 )
						//if(area3>0 )
						{
							m_DetectionRect[i].erase(itor);
							if(i==ii && itor < itor1)
								itor1--;
						}
						else
							itor++;
					}
					else
						itor++;
				}
			}
			//assert(nSubModel==0);
			CPosition pos2(itor1->x,itor1->y,1,0);
			//ReSampleAt(itor1->x, itor1->y, m_nWindowSize[ii]);
			m_MergeRect[ii].push_back(pos2);
			itor1 = m_DetectionRect[ii].erase(itor1);
		}
		
	}while(!bMergeOver);
	return TRUE;
}

BOOL CFaceFinder::merge1()
{
	int i, ii, count=0;

	int nSum = 0;
	for (i=m_nMaxScaleNum-1; i>=0; i--)
		nSum += m_DetectionRect[i].size();

	int nMinDetections;

	// rule0: if there are no RECT, do not merge
	if(nSum == 0)
		return FALSE;

	// rule1: if there only one RECT, remove it
	if(nSum == 1)
	{
		std::vector<CPosition>::iterator itor;
		for( i = 0; i < m_nMaxScaleNum; i++ )
			m_DetectionRect[i].clear();
		return FALSE;
	}
	// end rule1

	// rule2: calculate overlap
	double stepsize = 3;
	//int eraseflag = 0;

	for(i = 0; i < m_nMaxScaleNum; i++)
	{
		std::vector<CPosition>::iterator itor = m_DetectionRect[i].begin();
		while(itor != m_DetectionRect[i].end())
		{
			std::vector<CPosition>::iterator itor1 = m_DetectionRect[i].begin();
			while(itor1 != m_DetectionRect[i].end())
			{
				if(itor1 == itor)
				{
					itor1++;
					continue;
				}
				if(abs(itor->x - itor1->x) <= stepsize && abs(itor->y - itor1->y) <= stepsize)
					itor->FlagIntraScale++;
				itor1++;
			}
			
			if(i + 1 < m_nMaxScaleNum)
			{
				itor1 = m_DetectionRect[i + 1].begin();
				while(itor1 != m_DetectionRect[i + 1].end())
				{
					if( itor1->x - itor->x <= stepsize * m_ScaleSize && itor1->y - itor->y <= stepsize * m_ScaleSize)
					{
						itor->FlagInterScale++;
						itor1->FlagInterScale++;
					}
					itor1++;
				}
			}

			if(i + 2 < m_nMaxScaleNum)
			{
				itor1 = m_DetectionRect[i + 2].begin();
				while(itor1 != m_DetectionRect[i + 2].end())
				{
					if( itor1->x - itor->x <= stepsize * m_ScaleSize * m_ScaleSize && itor1->y - itor->y <= stepsize * m_ScaleSize * m_ScaleSize)
					{
						itor->FlagInterScale++;
						itor1->FlagInterScale++;
					}
					itor1++;
				}
			}

			itor++;
		}
		stepsize *= m_ScaleSize;
	}

	//remove non-overlapped rects
	for(i = 0; i < m_nMaxScaleNum; i++)
	{
		std::vector<CPosition>::iterator itor = m_DetectionRect[i].begin();
		while(itor != m_DetectionRect[i].end())
		{
			if( itor->FlagInterScale + itor->FlagIntraScale == 0 )
				m_DetectionRect[i].erase(itor);
			itor++;
		}
	}

	//merge
	int tmpx, tmpy, x, y;
	int WinSize = 0;
	//int nCnt = 1;
	int nCntOut = 1;
	stepsize = 3;
	tmpx = tmpy = x = y = 0;

	std::vector<CPosition> mergestep;

	for(i = 0; i < m_nMaxScaleNum; i++)
	{
		std::vector<CPosition>::iterator itor = m_DetectionRect[i].begin();
		while(itor != m_DetectionRect[i].end())
		{
			tmpx = itor->x;
			tmpy = itor->y;
			WinSize = m_nWindowSize[i];

			std::vector<CPosition>::iterator itor1 = m_DetectionRect[i].begin();
			while(itor1 != m_DetectionRect[i].end())
			{
				if(itor1 == itor)
				{
					itor1++;
					continue;
				}
				if(abs(itor->x - itor1->x) <= stepsize && abs(itor->y - itor1->y) <= stepsize)
				{
					tmpx += itor1->x;
					tmpy += itor1->y;
					WinSize += m_nWindowSize[i];

					//m_DetectionRect[i].erase(itor1);
					//nCnt++;
					nCntOut++;
				}
				itor1++;
			}
			//x = tmpx / nCnt;
			//y = tmpy / nCnt;

			//nCnt = 1;
			//tmpx = tmpy = 0;
			if(i + 1 < m_nMaxScaleNum)
			{
				itor1 = m_DetectionRect[i + 1].begin();
				while(itor1 != m_DetectionRect[i + 1].end())
				{
					if( itor1->x - itor->x <= stepsize * m_ScaleSize && itor1->y - itor->y <= stepsize * m_ScaleSize)
					{
						tmpx += itor1->x;
						tmpy += itor1->y;
						WinSize += m_nWindowSize[i];
						
						//m_DetectionRect[i].erase(itor1);
						//nCnt++;
						nCntOut++;
					}
					itor1++;
				}
				//x += tmpx / nCnt;
				//y += tmpy / nCnt;
			}

			//nCnt = 1;
			//tmpx = tmpy = 0;
			if(i + 2 < m_nMaxScaleNum)
			{
				itor1 = m_DetectionRect[i + 2].begin();
				while(itor1 != m_DetectionRect[i + 2].end())
				{
					if( itor1->x - itor->x <= stepsize * m_ScaleSize * m_ScaleSize && itor1->y - itor->y <= stepsize * m_ScaleSize * m_ScaleSize)
					{
						tmpx += itor1->x;
						tmpy += itor1->y;
						WinSize += m_nWindowSize[i];
						
						//m_DetectionRect[i].erase(itor1);
						//nCnt++;
						nCntOut++;
					}
					itor1++;
				}
				//x += tmpx / nCnt;
				//y += tmpy / nCnt;
			}

			x = tmpx / nCntOut;
			y = tmpy / nCntOut;
			WinSize /= nCntOut;

			itor = m_DetectionRect[i].erase(itor);
			//itor++;

			CPosition pos(x, y, 1, 0);
			pos.width = WinSize;
			pos.height = WinSize;

			int area1 = pos.width * pos.height;
			int area2;
			bool isin = false;
			if(!mergestep.empty())
			{
				std::vector<CPosition>::iterator itor2 = mergestep.begin();
				while(itor2 != mergestep.end())
				{
					area2 = OverlapRect(pos.y, pos.y + pos.height, pos.x, pos.x + pos.width, itor2->y, itor2->y + itor2->height, itor2->x, itor2->x + itor2->width);
					if(double(area2)/double(area1) >= 0.7)
					{
						isin = true;
						itor2->x = (itor2->x + pos.x) / 2;
						itor2->y = (itor2->y + pos.y) / 2;
						itor2->width = (itor2->width + pos.width) / 2;
						itor2->height = (itor2->height + pos.height) / 2;
						break;
					}
					itor2++;
				}
				if(!isin)
					mergestep.push_back(pos);
			}
			else
				mergestep.push_back(pos);
		}
		stepsize *= m_ScaleSize;
	}

	std::vector<CPosition>::iterator itor2 = mergestep.begin();
	while(itor2 != mergestep.end())
	{
		m_MergeRect[0].push_back(*itor2);
		itor2++;
	}

	return TRUE;
}

void CFaceFinder::GetGrayImg(BYTE **ppImg, const int nWidth, const int nHeight)
{
	int nTmp = 0;

	for (int i = 0; i < nWidth; i++)
	{
		nTmp = 0;
		for (int j = 0; j < nHeight; j++)
		{
			m_ppGrayImg[i][j] = BYTE( m_rgbBToY[ppImg[i][nTmp+0]]
							        + m_rgbGToY[ppImg[i][nTmp+1]]
							        + m_rgbRToY[ppImg[i][nTmp+2]] + 0.5);
			nTmp += 3;
		}
	}
}

void CFaceFinder::SetColorModel(BOOL bColor)
{
	m_bColor = bColor;
	
	if(m_bColor)
	{
		if(!m_ppFiImg)  m_ppFiImg  = New_2D(m_nWidth, m_nHeight); 
		if(!m_ppFaiImg) m_ppFaiImg = New_2D(m_nWidth, m_nHeight);
	}
	else
	{
		if(m_ppFiImg)  SAFE_RELEASE2(m_ppFiImg , m_nWidth); 
		if(m_ppFaiImg) SAFE_RELEASE2(m_ppFaiImg, m_nWidth); 
		m_ppFiImg  = NULL;
		m_ppFaiImg = NULL;
	}
}

void CFaceFinder::SetMinSize(int  nStdImageSize)
{
	m_nStdImageSize = nStdImageSize;
}

void CFaceFinder::SetMaxScale(int nMaxScaleNum)
{
	m_nMaxScaleNum = nMaxScaleNum;
}

void CFaceFinder::SetStep(int nStep)
{
	m_nStep = nStep;
}

void CFaceFinder::SetMerge(BOOL bMerge)
{
	m_bMerge = bMerge;
}

void CFaceFinder::SetMaxLayerNum(int nLayerNum)
{
	m_nMaxLayerNum = nLayerNum;
}



int CFaceFinder::GetMinSize()
{
	return m_nStdImageSize;
}

int CFaceFinder::GetMaxScale()
{
	return m_nMaxScaleNum;
}

int CFaceFinder::GetStep()
{
	return m_nStep;
}

BOOL CFaceFinder::GetMerge()
{
	return m_bMerge;
}

int CFaceFinder::GetMaxLayerNum()
{
	return m_nMaxLayerNum;
}

CString CFaceFinder::GetModelName()
{
	return m_CurModelPath;
}

BOOL CFaceFinder::GetColor()
{
	return m_bColor;
}

BOOL CFaceFinder::JudgeImage(int StartX, int StartY, int winsizeX, int winsizeY)
{
	int i, j;
	int i_Fai, i_Fi;
	int PixelNumber = 0;
	int ImageSize = winsizeX * winsizeY;
	int k1=46 , b1=-3685, k2=-76, b2=33219, y1, y2; 
	for(i = 0; i < winsizeX;  i++)
		for(j = 0; j < winsizeY;  j++)
		{
			i_Fai = m_ppFaiImg[i+StartX][j+StartY];
			i_Fi  = m_ppFiImg[i+StartX][j+StartY];
			
			/***************************************************/
			
			if((i_Fi>147)&&(i_Fi<303))
			{
				y1=k1*i_Fai+b1;
				y2=k2*i_Fai+b2; 
				if((i_Fai*100>y1)&&(i_Fai*100<y2))
					PixelNumber++;
					/*   
					int   k1=46;
					int   b1=-3685;
					int   k2=-76;
					int   b2=33219;
					int   y1=k1*Fai+b1;
					int   y2=k2*Fai+b2; 
					if((Fai>y1)&&(Fai<y2))
				PixelNumber++;*/
			}
			
		} 
		float ColorPercent=float(PixelNumber)/ImageSize;
		if( ColorPercent>0.4)
			return TRUE;
		else 
			return FALSE;
		
}

void CFaceFinder::GetFiFaiImg(BYTE **ppImg, const int nWidth, const int nHeight)
{
	int nTmp = 0;
	float u, v, t, f;
	for (int i = 0; i < nWidth; i++)
	{
		nTmp = 0;
		for (int j = 0; j < nHeight; j++)
		{
			m_ppFiImg[i][j] = int( m_rgbRToFI[ppImg[i][nTmp+2]]
							        + m_rgbGToFI[ppImg[i][nTmp+1]]
							        + m_rgbBToFI[ppImg[i][nTmp+0]] + 0.5)+152;
			u =  m_rgbRToU[ppImg[i][nTmp+2]]
							        + m_rgbGToU[ppImg[i][nTmp+1]]
							        + m_rgbBToU[ppImg[i][nTmp+0]] + 0.5;
			v =  m_rgbRToV[ppImg[i][nTmp+2]]
							        + m_rgbGToV[ppImg[i][nTmp+1]]
							        + m_rgbBToV[ppImg[i][nTmp+0]] + 0.5;
			if(u == 0.0)
			{
				t = 0;
			}
			else
			{
				f = atan( v / u );
				if(u > 0)
				{
					if( v < 0 )
						t = f + 6.2831853;
					else
						t = f;
				}
				else
				{
					t = f + 3.1415926;
				}
			}
			
			t *= (float)( 180 / 3.1415926 );
			m_ppFaiImg[i][j] = (int)t;

			nTmp += 3;
		}
	}
}

BOOL CFaceFinder::SetThreshold(float fRatio)
{
	for(int i =0 ; i< m_nModel ; i++)
	{
		if(m_pArrModel[i]==NULL)
			continue;
		double *pThreshold = m_pArrModel[i]->finalthreshold;
		if(!pThreshold)
			return FALSE;
		int nLayerNum = m_pArrModel[i]->m_nMaxLayNum;
		for(int j=0; j<nLayerNum; j++)
		{
			pThreshold[j] =TrshHold[j] * fRatio;
		}
	}

	m_fRatio = fRatio;
	return TRUE;
}

float CFaceFinder::GetThrRatio()
{
	return m_fRatio;
}

void CFaceFinder::SeStartScal(double dbStartscale)
{
	m_ScaleSize=dbStartscale;
}

double CFaceFinder::GetStartScale()
{
	return m_ScaleSize;
}

BOOL CFaceFinder::GetConfidence()
{
	return m_bConfidence;
}

void CFaceFinder::SetConfidence(BOOL bConf)
{
	m_bConfidence = bConf;
}
//do resample before merge
// for a face we do resample on this faces
void CFaceFinder::ReSample()
{
	std::vector<CPosition>::iterator itor, itor1;
	for (int i=0; i<m_nMaxScaleNum; i++)
	{
		float allConf;
		float MulticConf[20];
		//The candidate face window with same size
		int iSize = m_DetectionRect[i].size();
		int k = 0;
		for(itor = m_DetectionRect[i].begin(), k=0; k < iSize;itor++, k++ )
		{
			int PosX = itor->x ;
			int PosY = itor->y ;
			//the following change the start points
			//do resample
			int w = int (m_nWindowSize[i] *0.01);
			//int minx, miny, maxx, maxy;
			//minx = (PosX -w>0)? PosX -w:0;
			//miny = (PosX -w>0)? PosX -w:0;
			for(int x= PosX -w; x <PosX + w; x++)
			for(int y= PosY -w; y <PosY + w; y++)
			{
				//test x ,y in the list now or not?
				BOOL bExit = FALSE;
				for(itor1 = m_DetectionRect[i].begin(); !bExit && itor1 <m_DetectionRect[i].end(); itor1++)
				{
					if(x == itor1->x && y == itor1->y)
						bExit = TRUE;
				}
				if(x<0 || y<0 || x+m_nWindowSize[i] > m_nWidth+1 || y+m_nWindowSize[i] > m_nHeight+1 )
					bExit = TRUE;
				// test resample result
				if(!bExit && IsFace(x,y,i,allConf,MulticConf))
				{
					CPosition pos(x,y,1,allConf);					
					for(int j=0; j<m_nMaxLayerNum ;j++)
						pos.MultiConf[j] = MulticConf[j];
					m_DetectionRect[i].push_back(pos);	
				}
			}
		}
	}
}

bool CFaceFinder::GetFaceConf(const int PosX, const int PosY, const int width, float &dbConfidence, float *pfConfidence)
{
	int WindowSize = width;

	int layer, t, tTh;
	double variance_scale, hTh, hvalue;
	if(PosX + width >= m_nWidth || PosY +width>=m_nHeight)
	{
		dbConfidence = -1;
		return FALSE;
	}
	double dbVariance = GetVariance(PosX, PosY, WindowSize, WindowSize);
	double fScale = WindowSize / (double)STDIMAGESIZE;
	int * pTmp;

	if (dbVariance > MIN_STD_VARIANCE)	
	{
		dbVariance     = sqrt(dbVariance);
//		variance_scale = dbVariance*m_dbScaleArea[ScaleNo];
		variance_scale = dbVariance*fScale*fScale;

		int featurescale[8000][4];
		for (t=0; t< m_nFeatureNum; t++)
		{
			featurescale[t][0] = int(m_pModel->finaltype[t][2]*fScale);
			featurescale[t][1] = int(m_pModel->finaltype[t][3]*fScale);
			featurescale[t][2] = int((m_pModel->finaltype[t][4]-1)*fScale);
			featurescale[t][3] = int((m_pModel->finaltype[t][5]-1)*fScale);
		}
		layer=1;

		hvalue=0;	
		
		do
		{
			t=m_pModel->cascade[layer-1];
			tTh=m_pModel->cascade[layer];
			hTh=m_pModel->finalthreshold[layer];
		
			while ((t<tTh))// && (hvalue<hTh))
			{
				pTmp = featurescale[t]; //m_pModel->featurescale[t][ScaleNo];

				if((m_pModel->finalh[t]*variance_scale > 
					GetFeatureValue(m_ItgImageX, 
					                m_pModel->finaltype[t][1],
									pTmp[0],
									pTmp[1],
									pTmp[2]+PosX,
									pTmp[3]+PosY)) != (m_pModel->finalsign[t]>0))
					hvalue+=m_pModel->apha[t];
				
				t++;
			}	
//			pfConfidence[layer-1] = hvalue / m_fConfThr[layer-1];
			pfConfidence[layer-1] = hvalue / (2*m_pModel->finalthreshold[layer]);
			layer++;
//		}while((layer <= m_nMaxLayerNum));
		}while( (layer <= m_nMaxLayerNum));//=m_pModel->m_nMaxLayNum));
		dbConfidence = hvalue /m_fConfThr[layer-2];

		if (hvalue>=m_pModel->finalthreshold[layer-1])
		{
/*			if(layer <= m_pModel->m_nMaxLayNum)
			{
				t=m_pModel->cascade[layer-1];
				tTh=m_pModel->cascade[layer];
				hTh=m_pModel->finalthreshold[layer];
				while (t<tTh)
				{
					pTmp = m_pModel->featurescale[t][ScaleNo];

					if((m_pModel->finalh[t]*variance_scale > 
						GetFeatureValue(m_ItgImageX, 
										m_pModel->finaltype[t][1],
										pTmp[0],
										pTmp[1],
								
								  pTmp[2]+PosX,
										pTmp[3]+PosY)) != (m_pModel->finalsign[t]>0))
						hvalue+=m_pModel->apha[t];
					
					t++;
				}		
			}*/
			return true;		
		}
	}
	
	return false;
}

double CFaceFinder::GetVariance(int x, int y, int winm, int winn)
{
	__int64 s1,s2;

	double dbVariance;

	s1 = m_ItgImageX[x+winm][y+winn]
	   + m_ItgImageX[x][y]
	   - m_ItgImageX[x+winm][y]
	   - m_ItgImageX[x][y+winn];

	s2 = m_ItgImageXX[x+winm][y+winn]
	   + m_ItgImageXX[x][y]
	   - m_ItgImageXX[x+winm][y]
	   - m_ItgImageXX[x][y+winn];
	int winArea = winm*winn;
/*	double dbTmp = m_nWindowArea[scalenum]*m_nWindowArea[scalenum];
	if(dbTmp != 0)
		dbVariance = (s2*m_nWindowArea[scalenum]-s1*s1)/dbTmp;
	else
		dbVariance = 1; */

	
	// ATTENTION: dbTmp is out of range !!
/*
	double dbTmp = m_nWindowArea[scalenum]*m_nWindowArea[scalenum];
	ASSERT(dbTmp!=0);
	*/
	dbVariance = (s2*winArea-s1*s1)/winArea/winArea;
	if(dbVariance < 0)
		dbVariance = -dbVariance; 
	
	if (dbVariance==0) 
		dbVariance=1;	

	return dbVariance;
}

void CFaceFinder::ReSampleAt(int x, int y, int width,float &ratio, float& avrConf)
{
//return;	
	int ShWin = width *0.08;
	int minx, maxx, miny, maxy;
	minx = MAX(x-ShWin, 0);
	maxx = MIN(x+ShWin, m_nWidth-width);
	miny = MAX(y-ShWin, 0);
	maxy = MIN(y+ShWin, m_nHeight-width);
	float conf,Mconf[20];
	FILE *fp;
	fp =fopen("resampleResult.txt","a");
	double  nOnes=0,sum=0;
	float sumConf = 0;
	float MultiConf[20];
	for(int i=0; i< m_nMaxLayerNum; i++)
		MultiConf[i] = 0;
	int stepsize=MAX(1,(int) (ShWin/2.0));
	for(int  i=minx; i<maxx; i+=stepsize)
	for(int j=miny; j<maxy; j+=stepsize)
//	int i=x,j=y;
	{
	for (float f=0.9; f<1.1; f+=0.04)
	{
		conf = 0;
		int k =GetFaceConf(i,j,(int)(width*f),conf,Mconf);
		if(fabs(conf+1)<0.00001) continue;
		double weight=1.0;//exp(-fabs(1-f));
		sum+=weight;
		nOnes+=k*weight;
		sumConf += conf*weight;
//		fprintf(fp, "x=%d y=%d width=%d conf=%f isface:%d\n",i,j,(int)(width*f),conf, k);
		for(int m=0; m< m_nMaxLayerNum; m++)
			MultiConf[m] += Mconf[m];
	}
//	fprintf(fp, "\n");
	}
	ratio = nOnes/(double) sum;
	avrConf = sumConf/(double) sum;
	fprintf(fp, "(x=%5d y=%5d w=%5d) -- %10.5f %10.5f ratio=%10.5f conf= %10.5f\n",
		x, y, width, nOnes,sum,nOnes/(double) sum, sumConf/(double) sum);
		for(int m=0; m< m_nMaxLayerNum; m++)
			fprintf(fp, "%f ", MultiConf[m]/sum);
		fprintf(fp,"**********************\n");
	fclose(fp);
}


void CFaceFinder::SaveBmpImg(CString szFileName, BYTE* pImg, int nWidth, int nHeight)
{
	BITMAPFILEHEADER bmfHdr;

	int nImgHeight=(nWidth+3)/4*4;
	int imageSize=nImgHeight*nHeight;
	
	BYTE *saveImage=new BYTE[imageSize];
	memset(saveImage,0,imageSize);
	for(int i=0;i<nHeight;i++)
		memcpy(saveImage+i*nImgHeight,pImg+i*nWidth,nWidth);

	bmfHdr.bfType=0x4d42; 
    bmfHdr.bfSize=imageSize+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD); 
    bmfHdr.bfReserved1=0; 
    bmfHdr.bfReserved2=0; 
    bmfHdr.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD); 

	BITMAPINFO *pInfo=(BITMAPINFO*)malloc(sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD));
	pInfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); 
    pInfo->bmiHeader.biWidth=nWidth; 
    pInfo->bmiHeader.biHeight=nHeight; 
    pInfo->bmiHeader.biPlanes=1; 
    pInfo->bmiHeader.biBitCount=8; 
    pInfo->bmiHeader.biCompression=BI_RGB; 
    pInfo->bmiHeader.biSizeImage=imageSize; 
    pInfo->bmiHeader.biXPelsPerMeter=0; 
    pInfo->bmiHeader.biYPelsPerMeter=0; 
    pInfo->bmiHeader.biClrUsed=0; 
    pInfo->bmiHeader.biClrImportant=0; 

  	for(int i=0;i<256;i++)
	{
		pInfo->bmiColors[i].rgbBlue=i;
		pInfo->bmiColors[i].rgbGreen=i;
		pInfo->bmiColors[i].rgbRed=i;
		pInfo->bmiColors[i].rgbReserved=0;
	}

	CFile mFile;
	mFile.Open(szFileName,CFile::modeCreate | CFile::modeWrite,NULL);
    mFile.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
    mFile.Write(pInfo,sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD));
	mFile.Write(saveImage,(DWORD)imageSize); 
	mFile.Close();

	delete[] saveImage;
	saveImage = NULL;
	
	free(pInfo);
}

BOOL CFaceFinder::LoadSModel(char *FileName)
{
	FILE *fp = fopen(FileName, "rb");
	if(fp == NULL) return FALSE;
	ReleaseSModel();
	m_nSModelNum = 0;
	while(!feof(fp) && m_nSModelNum<1)
	{
		int dim;
		BYTE bTmp=fread(&dim, sizeof(int),1,fp);
		if(!bTmp|| dim <=0) break; 
		m_SModelArr[m_nSModelNum].FeatureNum = dim;
		m_SModelArr[m_nSModelNum].w = new double[dim];
		m_SModelArr[m_nSModelNum].pFeature = new double[dim];
		m_SModelArr[m_nSModelNum].featurescale = new int[dim][MAX_SCALE][4];
		m_SModelArr[m_nSModelNum].finaltype = new int[dim][6];
		for(int i=0; i<dim ; i++)
		{
			fread(m_SModelArr[m_nSModelNum].finaltype[i], sizeof(int), 5, fp);

		}
		fread(m_SModelArr[m_nSModelNum].w, sizeof(double), dim, fp);
		fread(&m_SModelArr[m_nSModelNum].bias,sizeof(double),1,fp);
		m_nSModelNum++;
	}
	fclose(fp);
	//adaboost model
	
	return TRUE;
	// feature to be loaded
}

void CFaceFinder::ReleaseSModel()
{
	for(int i =0 ; i <m_nSModelNum  ;i ++)
	{
		if(m_SModelArr[i].w )
		{
			delete m_SModelArr[i].w;
			m_SModelArr[i].w = NULL;
		}
		if(m_SModelArr[i].pFeature)
		{
			delete m_SModelArr[i].pFeature;
			m_SModelArr[i].pFeature = NULL;
		}
		if(m_SModelArr[i].finaltype)
		{
			delete []m_SModelArr[i].finaltype;
			m_SModelArr[i].finaltype = NULL;
		}
		if(m_SModelArr[i].featurescale)
		{
			delete []m_SModelArr[i].featurescale;
			m_SModelArr[i].featurescale = NULL;
		}
	}
}

bool CFaceFinder::IsFace1(const int PosX, const int PosY, const int ScaleNo, float &dbConfidence, int nLayer)
{
	int WindowSize = m_nWindowSize[ScaleNo];

	int layer, t, tTh ;
	double variance_scale, hTh, hvalue;
	
	double dbVariance = GetVariance(ScaleNo, PosX, PosY, WindowSize, WindowSize);
	if(nLayer == -100) dbVariance = 1;

	int * pTmp;

	if (dbVariance > MIN_STD_VARIANCE) 
	{
		dbVariance     = sqrt(dbVariance);
		variance_scale = dbVariance*m_dbScaleArea[ScaleNo];
		
		for( int i =0 ; i< m_nModel; i++)
		{

			if(m_pArrModel[i]==NULL)
			{
				continue;
			}

			layer=1; 
			hvalue=0;	

			m_nAbsFea = m_pArrModel[i]->abs;
			int mir = 0;
			if(m_nAbsFea==0)
			{
				int m, n;
				n = m_nWindowSize[ScaleNo];
				m = n >> 1;
				if(GetFeatureValue(m_ItgImageX, 1, m, n, PosX, PosY) < 0)
					mir = 1;
			}
			do
			{

				t=m_pArrModel[i]->cascade[layer-1];
				tTh=m_pArrModel[i]->cascade[layer];
				hTh=m_pArrModel[i]->finalthreshold[layer];
			
				while ((t<tTh))
				{
					pTmp = m_pArrModel[i]->featurescale[t][ScaleNo];
					
					if((m_pArrModel[i]->finalh[t]*variance_scale > 
						GetFeatureValue(m_ItgImageX, 
										m_pArrModel[i]->finaltype[t][1],
										pTmp,
										PosX,
										PosY,
										ScaleNo,mir,m_nAbsFea)) != (m_pArrModel[i]->finalsign[t]>0))
						
						
						hvalue+=m_pArrModel[i]->apha[t];
						
					t++;
				}	
				layer++;
			}while((hvalue>=m_pArrModel[i]->finalthreshold[layer-1]) && (layer <= m_pArrModel[i]->m_nMaxLayNum));//m_nSModelLayer));
			if(hvalue<m_pArrModel[i]->finalthreshold[layer-1]) 
				return false;
			//tested the mirror images
			if(m_bMirror && m_nAbsFea==1)
			{
				layer=1;
				hvalue=0;				
				do
				{
					t=m_pArrModel[i]->cascade[layer-1];
					tTh=m_pArrModel[i]->cascade[layer];
					hTh=m_pArrModel[i]->finalthreshold[layer];
				
					while ((t<tTh))// && (hvalue<hTh))
					{
						pTmp = m_pArrModel[i]->featurescale[t][ScaleNo];
						int x = GetMirrorFeatureX(pTmp[2], pTmp[0], WindowSize, m_pArrModel[i]->finaltype[t][1]);
						int type1 = m_pArrModel[i]->finaltype[t][1];
						int sign = 1;
						if(m_nAbsFea == 0)
							sign = MirSign[type1];
						int pp[4];
						pp[0] = pTmp[0];
						pp[1] = pTmp[1];
						pp[3] = pTmp[3];
						pp[2] = x;
						int mir2 = abs(1-mir);
						if((m_pArrModel[i]->finalh[t]*variance_scale > 
						 sign*GetFeatureValue(m_ItgImageX, 
										MirType[type1],
										pp,
										PosX,
										PosY,
										ScaleNo,mir2,m_nAbsFea)) != (m_pArrModel[i]->finalsign[t]>0))
					

						hvalue+=m_pArrModel[i]->apha[t];
						
						t++;
					}
					layer++;
				}while((hvalue>=m_pArrModel[i]->finalthreshold[layer-1]) && (layer <= m_pArrModel[i]->m_nMaxLayNum));//=m_pModel->m_nMaxLayNum));
				if (hvalue<m_pArrModel[i]->finalthreshold[layer-1]) 
					return false;
			}
		}
		return true;
	}
	return false;
}


BOOL CFaceFinder::GetSModel()
{
	return m_bSModel;
}

void CFaceFinder::SetSModel(BOOL bsModel)
{
	m_bSModel = bsModel;
}

int CFaceFinder::GetSModelLayer()
{
	return m_nSModelLayer;
}	

void CFaceFinder::SetSModelLayer(int nLayer)
{
	m_nSModelLayer = nLayer;
}
Found_Face * pRois = NULL;
RECT g_rcFace[10];
Found_Face * CFaceFinder::DownDoFaceFinder(BYTE **ppImgOrg, const int nWidthOrg, const int nHeightOrg, BOOL bMirror)
{
	m_bMirrorDlg = bMirror;

	for(int nScale = 0; nScale < m_nMaxScaleNum; nScale++)
	{
		m_DetectionRect[nScale].clear();
		m_MergeRect[nScale].clear();
	}

	int px, py, winsize, i, scalenum, MaxSize;

	double step;
	double scale;
	int count;
//the follwoing to do down sample for original images if the original images are too large
	int DownSampleNum = MIN(nWidthOrg, nHeightOrg);
	DownSampleNum = DownSampleNum/600;
	if(DownSampleNum == 0)
		DownSampleNum =1;

	int nWidth  = nWidthOrg/DownSampleNum;
	int nHeight = nHeightOrg/DownSampleNum;
	BYTE **ppImg;
	if(DownSampleNum!=1)
	{
		ppImg = New_2D2(nWidth,  nHeight*3);
		for(int i = 0; i< nHeight ; i++)
		for(int j = 0; j< nWidth  ; j++)
		{
			int i1 = i*DownSampleNum;
			int j1 = j*DownSampleNum;
			ppImg[j][i*3] = ppImgOrg[j1][i1*3];
			ppImg[j][i*3+1] = ppImgOrg[j1][i1*3+1];
			ppImg[j][i*3+2] = ppImgOrg[j1][i1*3+2];
		}
	}
	else
	{
		ppImg = ppImgOrg;
	}
	if(m_nHeight != nHeight || m_nWidth != nWidth)
	{
		SAFE_RELEASE2(m_ItgImageX,  m_nWidth+1);
		SAFE_RELEASE2(m_ItgImageXX, m_nWidth+1);
		SAFE_RELEASE3(m_ppGrayImg,  m_nWidth);
		if(m_bColor)
		{
			SAFE_RELEASE2(m_ppFiImg , m_nWidth); 
			SAFE_RELEASE2(m_ppFaiImg, m_nWidth); 
		}
		m_nHeight = nHeight;
		m_nWidth  = nWidth;
		
		m_ItgImageX  = New_2D(m_nWidth+1, m_nHeight+1);
		m_ItgImageXX = New_2D(m_nWidth+1, m_nHeight+1);
		m_ppGrayImg  = New_2D2(m_nWidth,  nHeight);

		if(m_bColor)
		{
			m_ppFiImg  = New_2D(m_nWidth, m_nHeight); 
			m_ppFaiImg = New_2D(m_nWidth, m_nHeight);
		}
	}

	MaxSize = MIN(m_nHeight, m_nWidth);

	GetGrayImg(ppImg, nWidth, nHeight);
	if(m_bColor)
		GetFiFaiImg(ppImg, nWidth, nHeight);
	if(DownSampleNum!=1)
	{
		SAFE_RELEASE3(ppImg,  nWidth);
	}	
	GetItgImage(m_ppGrayImg, nWidth, nHeight);

	// ATTENTION: questions???????????????
	// this part change for start with big face
	//the follwoing part is changed by QiaoYU 2002-10-09
	if(m_nStdImageSize == 0)
		m_nStdImageSize = max(30, MaxSize/30);
//	m_nStdImageSize = max(24, MaxSize*0.04);

	m_dbStartscale    = PrepareModel(m_nStdImageSize);
	m_OriStdImageSize = m_nStdImageSize;

//end of change
	scale    = m_dbStartscale;
	step     = STARTSTEP*m_dbStartscale;
	scalenum = 0;

	float dbConfidence = 0.0f;
	float pMultiConf[10]={0.0f};
//	int g_count = 0;


	do
	{				
		winsize = m_nWindowSize[scalenum];			
		px=0;
		while((px+winsize<m_nWidth+1))
		{
			py=0;
			while((py+winsize<m_nHeight+1))
			{	
		 
				BOOL bRsl;
 
				if( m_nMethodThr==0 )
					bRsl = IsFace1(px, py, scalenum, dbConfidence, m_nSModelLayer);
				else if( m_nMethodThr==4 )
				{
					m_nModel = 1;
					bRsl = IsFace1(px, py, scalenum, dbConfidence, m_nSModelLayer);
					m_nModel = 2;
				}
				else
					bRsl = IsFace3(px, py, scalenum, pMultiConf, m_nSModelLayer);
				if( bRsl )		//		if(GetFaceConf(px, py, winsize, dbConfidence, fMultiConf))
				{
					BOOL bPush = TRUE;
					reg_count++;
					if(m_bColor)
					{
						bPush = JudgeImage(px, py, winsize, winsize);
					}

					if(bPush)
					{
						CPosition pos(px,py,1,dbConfidence);					
						//for(int i=0; i<m_nMaxLayerNum ;i++)
						//	pos.MultiConf[i] = fMultiConf[i];
						pos.MultiConf[0] = pMultiConf[0];
						pos.MultiConf[1] = pMultiConf[1];
						pos.MultiConf[2] = pMultiConf[2];
						m_DetectionRect[scalenum].push_back(pos);
						// add pca method 
						// crop images for svm testing
					}	
				}			
				py+=int(step)+m_nStep;
			}
			px+=int(step)+m_nStep; 
		}

		scale *= m_ScaleSize;
		step  *= m_ScaleSize;
		scalenum++;

	}while ((scalenum<m_nMaxScaleNum)); //MAX_SCALE
	BOOL bMergeResult = FALSE;
	if(m_bMerge)
	{
		bMergeResult = merge();
	}
	if(bMergeResult == FALSE || m_bMerge == FALSE)
	{
		for(int nScale = 0; nScale < m_nMaxScaleNum; nScale++)
		{
			m_MergeRect[nScale].clear();
			for(int k = 0; k < m_DetectionRect[nScale].size(); k++)
			m_MergeRect[nScale].push_back(m_DetectionRect[nScale][k]);
		}
	}

	count=0;
	for(i=0;i<m_nMaxScaleNum;i++)
		count += m_MergeRect[i].size();

//	Found_Face * pRois=NULL;
	if(pRois==NULL)
		pRois =new Found_Face;

	

	if(count != 0)
	{
		pRois->dwNumROI = count;
		pRois->rcROI = g_rcFace;//new RECT[pRois->dwNumROI];
		
		int k = 0;
		std::vector<CPosition>::reverse_iterator itor;
		
		for ( i=0; i<MAX_SCALE; i++) 
		{
			for(itor = m_MergeRect[i].rbegin(); itor != m_MergeRect[i].rend(); itor++)
			{
//				float ratio, avrConf;
//				ReSampleAt(itor->x, itor->y, m_nWindowSize[i], ratio, avrConf);
				pRois->rcROI[k].left    = itor->x *DownSampleNum;
				pRois->rcROI[k].top     = itor->y *DownSampleNum;
				pRois->rcROI[k].right   = (itor->x + m_nWindowSize[i]) *DownSampleNum;
				pRois->rcROI[k].bottom  = (itor->y + m_nWindowSize[i]) *DownSampleNum;
//				pRois->rcROI[k].ratio   = ratio;
//				pRois->rcROI[k].avrConf = avrConf;

				k++;

				if(k>10) break;
			}
			
			m_MergeRect[i].erase(m_MergeRect[i].begin(), m_MergeRect[i].end());
		}
	}
	else
	{
		pRois->dwNumROI=0;
		pRois->rcROI=NULL;
	}

	return pRois;
}


inline BOOL CFaceFinder::StrongClassify(PCAModel & m_PCAModel, float* pVector)
{
	int i;
	double s = 0;

	for (i = 0; i < m_PCAModel.FeatureNum; i++)	
	{
		int k = m_PCAModel.SelectFea[i];
		if((pVector[k] > m_PCAModel.Threshold[i]) == (m_PCAModel.Sign[i]>0) )
			s+=m_PCAModel.apha[i];//*(SimpleClassify(pVector, m_PCAModel.SelectFea[i], i)==1);
	}
	if(s >= m_PCAModel.finalThr)
		return  TRUE;
	else 
		return FALSE;
}

int CFaceFinder::SimpleClassify(float* pVector, int nFeaId, int nWeakId)
{
	if( (pVector[nFeaId] - m_PCAModel.Threshold[nWeakId])*m_PCAModel.Sign[nWeakId] > 0)
		return 1;
	else
		return -1;
}

BOOL CFaceFinder::LoadPCAModel( CString filename)
{
	FILE *stream;		
	int WeakLearnerNum;
	float FinalThreshold;
	stream=fopen(filename,"r");	
	m_nPCAModel = 4;
	for(int j=0; j<4; j++)
	{
		fscanf(stream,"%d %f ", &WeakLearnerNum, &FinalThreshold);
		m_PCAModelArr[j].FeatureNum = WeakLearnerNum;
		m_PCAModelArr[j].finalThr = FinalThreshold;
		float error;
		for (int i=0; i<WeakLearnerNum; i++)
		{
			fscanf(stream,"%d %f %d %f %f\n",
			&m_PCAModelArr[j].SelectFea[i],
			&m_PCAModelArr[j].Threshold[i],
			&m_PCAModelArr[j].Sign[i],
			&m_PCAModelArr[j].apha[i], 
			&error
			);
		}
	}
	fclose(stream);
	return TRUE;
}

BOOL CFaceFinder::GetPCA()
{
	return m_bPCA;
}

void CFaceFinder::SetPCA(BOOL bPCA)
{
	m_bPCA = bPCA;
}

inline int CFaceFinder::GetMirrorFeatureX(int x, int mm, int width, int type)
{
	int r = -1;
	switch(type)
	{
		case 1:
		case 4:
		case 5:
		case 6:
			r = width - x-mm-mm;
			break;
		case 2:
			r = width -x-mm;
			break;
		case 3:
			r = width - x-mm-mm-mm;
			break;
	}
	if(r<0)
		return 0;
	return r;
}

BOOL CFaceFinder::GetMirror()
{
	return m_bMirror;
}

void CFaceFinder::SetMirror(BOOL bMir)
{
	m_bMirror = bMir;
}

inline bool CFaceFinder::IsFace2(const int PosX, const int PosY, const int ScaleNo, float &dbConfidence, int nLayer)
{
	int WindowSize = m_nWindowSize[ScaleNo];

	int layer, t, tTh ;
	double variance_scale, hTh, hvalue;

	double dbVariance = GetVariance(ScaleNo, PosX, PosY, WindowSize, WindowSize);
	int * pTmp;

	if (dbVariance > MIN_STD_VARIANCE)	
	{
		dbVariance     = sqrt(dbVariance);
		variance_scale = dbVariance * m_dbScaleArea[ScaleNo];
///*
		for( int i =0 ; i<m_nModel; i++)
		{
			if(m_pArrModel[i]==NULL)
				continue;
			// tested the orginal images
			layer=1; 
			hvalue=0;	
			
			do
			{
				t=m_pArrModel[i]->cascade[layer-1];
				tTh=m_pArrModel[i]->cascade[layer];
				hTh=m_pArrModel[i]->finalthreshold[layer];
			
				while ((t<tTh))// && (hvalue<hTh))
				{
					pTmp = m_pArrModel[i]->featurescale[t][ScaleNo];

					if((m_pArrModel[i]->finalh[t]*variance_scale > 
						GetFeatureValue(m_ItgImageX, 
										m_pArrModel[i]->finaltype[t][1],
										pTmp[0],
										pTmp[1],
										pTmp[2]+PosX,
										pTmp[3]+PosY)) != (m_pArrModel[i]->finalsign[t]>0))
						hvalue+=m_pArrModel[i]->apha[t];
					
					t++;
				}	
				layer++;
			}while((hvalue>=m_pArrModel[i]->finalthreshold[layer-1]) && (layer <= m_pArrModel[i]->m_nMaxLayNum));//m_nSModelLayer));
			if (hvalue<m_pArrModel[i]->finalthreshold[layer-1]) return false;
		}
		if(m_bMirror)
		{
			for(int i =0 ; i<m_nModel; i++)
			{
				if(m_pArrModel[i]==NULL)
					continue;
				//tested the mirror images
				layer=1;
				hvalue=0;				
				do
				{
					t=m_pArrModel[i]->cascade[layer-1];
					tTh=m_pArrModel[i]->cascade[layer];
					hTh=m_pArrModel[i]->finalthreshold[layer];
					
					while ((t<tTh))// && (hvalue<hTh))
					{
						pTmp = m_pArrModel[i]->featurescale[t][ScaleNo];
						int x = GetMirrorFeatureX(pTmp[2], pTmp[0], WindowSize, m_pArrModel[i]->finaltype[t][1]);
						int type1 = m_pArrModel[i]->finaltype[t][1];
						if((m_pArrModel[i]->finalh[t]*variance_scale > 
							MirSign[type1]*GetFeatureValue(m_ItgImageX, 
											MirType[type1],
											pTmp[0],
											pTmp[1],
											x+PosX,
											pTmp[3]+PosY)) != (m_pArrModel[i]->finalsign[t]>0))//
							hvalue+=m_pArrModel[i]->apha[t];
							
							t++;
					}
					layer++;
				}while((hvalue>=m_pArrModel[i]->finalthreshold[layer-1]) && (layer <= m_pArrModel[i]->m_nMaxLayNum));//=m_pModel->m_nMaxLayNum));
				if (hvalue<m_pArrModel[i]->finalthreshold[layer-1]) return false;
			}
		}
	}
	else
	{
		return false;
	}
	return true;
}

inline int CFaceFinder::ChooseMdl(int **itgimage, const int PosX, const int PosY, const int WinSize)
{
	//calculate the two features
	//feturea 1 ---updown 2-----middle
	float fea1 = GetFeatureValue(itgimage, 2, WinSize, WinSize/2, PosX, PosY);
	float fea2 = GetFeatureValue(itgimage, 3, WinSize*6/20, WinSize*18/20, PosX+WinSize/20, PosY);
	//threshold
	const double th_fea1 = 17.0, th_fea2 = 62.0;
	if (fea1 > th_fea1 && fea2 > th_fea2)
		return 1;
	else if (fea1 <= th_fea1 && fea2 > th_fea2)
		return 2;
	else if (fea1 <= th_fea1 && fea2 <= th_fea2)
		return 3;
	else  // if (x > t_x && y <=t_y )
		return 4;	
}

BOOL CFaceFinder::IsFaceSubMdl(const int PosX, const int PosY, const int ScaleNo)
{
	int WindowSize = m_nWindowSize[ScaleNo];
	int k =ChooseMdl(m_ItgImageX, PosX, PosY, WindowSize);
	Model* pModel = m_pArrModel[k-1];
	int layer, t, tTh;
	double variance_scale, hTh, hvalue;

	double dbVariance = GetVariance(ScaleNo, PosX, PosY, WindowSize, WindowSize);

	int * pTmp;

//	if (dbVariance > MIN_STD_VARIANCE)	
	{
		dbVariance     = sqrt(dbVariance);
		variance_scale = dbVariance*m_dbScaleArea[ScaleNo];

		layer=1;

		hvalue=0;							
		
		do
		{
			t=pModel->cascade[layer-1];
			tTh=pModel->cascade[layer];
			hTh=pModel->finalthreshold[layer];
		
			while ((t<tTh))// && (hvalue<hTh))
			{
				pTmp = pModel->featurescale[t][ScaleNo];

				if((pModel->finalh[t]*variance_scale > 
					GetFeatureValue(m_ItgImageX, 
					                pModel->finaltype[t][1],
									pTmp[0],
									pTmp[1],
									pTmp[2]+PosX,
									pTmp[3]+PosY)) != (pModel->finalsign[t]>0))
					hvalue += pModel->apha[t];
				
				t++;
			}	
//			pfConfidence[layer-1] = hvalue / m_fConfThr[layer-1];
//			pfConfidence[layer-1] = hvalue / (2*m_pModel->finalthreshold[layer]);m_pModel->m_nMaxLayNum
			layer++;
//		}while((layer <= m_nMaxLayerNum));
		}while((layer>10 || hvalue>=pModel->finalthreshold[layer-1]) && (layer <= pModel->m_nMaxLayNum));//m_nMaxLayerNum));//=pModel->m_nMaxLayNum));
		if(m_bMirror)
		{
			layer=1;
			hvalue=0;				
			do
			{
				t=pModel->cascade[layer-1];
				tTh=pModel->cascade[layer];
				hTh=pModel->finalthreshold[layer];
			
				while ((t<tTh))// && (hvalue<hTh))
				{
					pTmp = pModel->featurescale[t][ScaleNo];
					int x = GetMirrorFeatureX(pTmp[2], pTmp[0], WindowSize, pModel->finaltype[t][1]);
					int type1 = pModel->finaltype[t][1];
					if((pModel->finalh[t]*variance_scale > 
						MirSign[type1]*GetFeatureValue(m_ItgImageX, 
										MirType[type1],
										pTmp[0],
										pTmp[1],
										x+PosX,
										pTmp[3]+PosY)) != (pModel->finalsign[t]>0))//
						hvalue+=pModel->apha[t];
					
						t++;
					}
					layer++;
				}while((hvalue>=pModel->finalthreshold[layer-1]) && (layer <= pModel->m_nMaxLayNum));//=m_pModel->m_nMaxLayNum));
				if (hvalue<pModel->finalthreshold[layer-1]) return false;
			}
		if (hvalue>=pModel->finalthreshold[layer-1])
		{
//			dbConfidence = hvalue /m_fConfThr[layer-2];
			return TRUE;		
		}
	}
	
	return FALSE;
}

void CFaceFinder::Test()
{

}

void CFaceFinder::Test1()
{

	CString strFileName ="g:\\Itg-26476.DB";
	FILE *fp;
	fp = fopen(strFileName.GetBuffer(strFileName.GetLength()), "rb");
	if(fp == NULL)
	{
		exit(0);
	}
	FILE *fpRlt = fopen("d:\\rslt.txt","w");

	m_ItgImageX  = New_2D(20+1, 20+1);
	m_ItgImageXX = New_2D(20+1, 20+1);
	m_ppGrayImg  = New_2D2(20,  20);
	m_nWidth = 20;
	m_nHeight = 20;
	PrepareModel(20);
	const int nWidth = 20;
	const int nHeight = 20;
	const int nLength = (nWidth + 1) * (nHeight + 1);

	float* pItgimg = new float [nLength];
	int b = 1;
	int k =0;
	int n=1;
	float f =0;
	while(!feof(fp) && b)
	{
		b = fread(pItgimg, sizeof(float), nLength, fp);
		if(b==0)
		{
			//MessageBox("Read File Error");
			break;
		}
		for(int i =0 ;i<21;i++)
		for(int j =0 ;j<21;j++)
			m_ItgImageX[i][j]= pItgimg[i*20+j];
		if(!IsFace1(0,0,0,f,-100))
			fprintf(fpRlt, "img %d \n",k);
		
		k++;
//			ShowBuffer(&dc, pImg, nWidth, nHeight);
//			ShowBuffer(&dc, pMirImg, nWidth, nHeight, nWidth+5);
		}
	CString msg;
	msg.Format("Totally %d images at all",k);
	AfxMessageBox(msg);
	fclose(fp);
	fclose(fpRlt);
	delete pItgimg;

}

bool CFaceFinder::IsFaceMir(const int PosX, const int PosY, const int ScaleNo)
{

	return false;

}

inline int CFaceFinder::GetFeatureValue(int **itgimage, int type, int *pos, int PosX, int PosY, const int ScaleNo, int mir, int absf)
{
	if(absf == 1)
	{
		int X = GetFeatureValue(itgimage, type, pos[0], pos[1], pos[2] + PosX, pos[3] + PosY);
		X=abs(X);
		return X;
	}
	if(mir == 1)
	{
		int m, n;
		n = m_nWindowSize[ScaleNo];
		m = n >> 1;
		
		{
			int pos2 = pos[2];
			switch(type)
			{
			case 1:
			case 4:
			case 5:
			case 6:
				pos2 = n - pos[2] - pos[0]*2;
				break;
			case 2:
				pos2 = n - pos[2] - pos[0];
				break;
			case 3:
				pos2 = n - pos[2] - pos[0]*3;
				break;
			}
			
			return MirSign[type] * GetFeatureValue(itgimage, MirType[type], pos[0], pos[1], pos2 + PosX, pos[3] + PosY);
		}
	}
	else
		return GetFeatureValue(itgimage, type, pos[0], pos[1], pos[2] + PosX, pos[3] + PosY);
}

inline bool CFaceFinder::IsFace3(const int PosX, const int PosY, const int ScaleNo, float *pConfidence, int nLayer)
{
	int WindowSize = m_nWindowSize[ScaleNo];

	int layer, t, tTh ;
	double variance_scale, hTh, hvalue;
	bool rrMir = TRUE;
	double dbVariance = GetVariance(ScaleNo, PosX, PosY, WindowSize, WindowSize);
	if(nLayer == -100) dbVariance = 1;
//	double dbMean=;
	int * pTmp;
	double value[4], valueMir[4];
	if (dbVariance > MIN_STD_VARIANCE) 
	{
		dbVariance     = sqrt(dbVariance);
		
	
		double comb_Conf = 0;
		for( int i =0 ; i< m_nModel; i++)
		{
			if(m_pArrModel[i]->finaltype[0][1]==7||m_pArrModel[i]->finaltype[0][1]==8)
				variance_scale = dbVariance;
			else
				variance_scale = dbVariance*m_dbScaleArea[ScaleNo];

			if(m_pArrModel[i]==NULL)
			{
				continue;
			}
			// tested the orginal images
			layer=1; 
			hvalue=0;	

			m_nAbsFea = m_pArrModel[i]->abs;
			int mir = 0;
			//if(m_nAbsFea==0)
		//{
			//	int m, n;
			//	n = m_nWindowSize[ScaleNo];
			//	m = n >> 1;
			//	if(GetFeatureValue(m_ItgImageX, 1, m, n, PosX, PosY) < 0)
			//		mir = 1;
		//	}
			if(m_nAbsFea==0)
			{
				do
				{
					 
					t=m_pArrModel[i]->cascade[layer-1];
					tTh=m_pArrModel[i]->cascade[layer];
					hTh=m_pArrModel[i]->finalthreshold[layer];
				
					while ((t<tTh))
					{
						pTmp = m_pArrModel[i]->featurescale[t][ScaleNo];
						
						if((m_pArrModel[i]->finalh[t]*variance_scale > 
							GetFeatureValue(m_ItgImageX, 
											m_pArrModel[i]->finaltype[t][1],
											pTmp,
											PosX,
											PosY,
											ScaleNo,mir,m_nAbsFea)) != (m_pArrModel[i]->finalsign[t]>0))
							
							hvalue+=m_pArrModel[i]->apha[t];
							
						t++;
					}	
					layer++;
				}while((hvalue>=m_pArrModel[i]->finalthreshold[layer-1]) && (layer <= m_pArrModel[i]->m_nMaxLayNum));
				if(hvalue<m_pArrModel[i]->finalthreshold[layer-1]) 
					return false;
				comb_Conf += hvalue/m_pArrModel[i]->finalthreshold[layer-1];
				value[i] = hvalue;
			}
			else if(m_nAbsFea==1)
			{
				//test original image
				do
				{
					//hvalue=0;	
					t=m_pArrModel[i]->cascade[layer-1];
					tTh=m_pArrModel[i]->cascade[layer];
					hTh=m_pArrModel[i]->finalthreshold[layer];
				
					while ((t<tTh))// && (hvalue<hTh))
					//while ((t<tTh) && (hvalue<hTh))
					{
						pTmp = m_pArrModel[i]->featurescale[t][ScaleNo];
						
						if((m_pArrModel[i]->finalh[t]*variance_scale > 
							GetFeatureValue(m_ItgImageX, 
											m_pArrModel[i]->finaltype[t][1],
											pTmp,
											PosX,
											PosY,
											ScaleNo,mir,m_nAbsFea)) != (m_pArrModel[i]->finalsign[t]>0))
							
							hvalue+=m_pArrModel[i]->apha[t];
							
						t++;
					}	
					layer++;
					if(hvalue<m_pArrModel[i]->finalthreshold[layer-1]) rrMir = FALSE;
				}while((layer <= m_pArrModel[i]->m_nMaxLayNum));//m_nSModelLayer));
				if(!rrMir) return false;
				if(!m_bMirror)
					comb_Conf += hvalue/m_pArrModel[i]->finalthreshold[layer-1];
				else
					comb_Conf += hvalue/m_pArrModel[i]->finalthreshold[layer-1]/2;

				value[i] = hvalue;
				//test mirror image
				if(m_bMirror)
				{
					layer=1;
					hvalue=0;				
					do
					{
						t=m_pArrModel[i]->cascade[layer-1];
						tTh=m_pArrModel[i]->cascade[layer];
						hTh=m_pArrModel[i]->finalthreshold[layer];
					
						while ((t<tTh))// && (hvalue<hTh))
						{
							pTmp = m_pArrModel[i]->featurescale[t][ScaleNo];
							int x = GetMirrorFeatureX(pTmp[2], pTmp[0], WindowSize, m_pArrModel[i]->finaltype[t][1]);
							int type1 = m_pArrModel[i]->finaltype[t][1];
							int sign = 1;
							if(m_nAbsFea == 0)
								sign = MirSign[type1];
							int pp[4];
							pp[0] = pTmp[0];
							pp[1] = pTmp[1];
							pp[3] = pTmp[3];
							pp[2] = x;
							int mir2 = abs(1-mir);
							if((m_pArrModel[i]->finalh[t]*variance_scale > 
							 sign*GetFeatureValue(m_ItgImageX, 
											MirType[type1],
											pp,
											PosX,
											PosY,
											ScaleNo,mir2,m_nAbsFea)) != (m_pArrModel[i]->finalsign[t]>0))
							hvalue+=m_pArrModel[i]->apha[t];
							
							t++;
						}
						layer++;
						if(hvalue<m_pArrModel[i]->finalthreshold[layer-1]) rrMir = FALSE;
					}while((layer <= m_pArrModel[i]->m_nMaxLayNum));//=m_pModel->m_nMaxLayNum));
					valueMir[i] = hvalue;
					if(!rrMir) return false;
					comb_Conf += hvalue/m_pArrModel[i]->finalthreshold[layer-1]/2;
				}
			}
		}
		if(!m_bUse4Layer || comb_Conf>=m_nModel*m_fRatio)
			return true;

	}
	return false;
}

void CFaceFinder::SetThrMethod(int nMethod)
{
	m_nMethodThr = nMethod;
}

int CFaceFinder::GetThrMethod()
{
	return m_nMethodThr;
}

int CFaceFinder::Calc_Sum(int x1, int y1, int x2, int y2, int **imgsum)
{
	return (imgsum[x2][y2]- imgsum[x2][y1] - imgsum[x1][y2] + imgsum[x1][y1]);
}

int CFaceFinder::CalSobel(int x, int y, int sizex, int sizey, int *Filter, int **imgsum)
{
	int result=0;														
	int move=1;//(int)((3-1)/2);								
	for(int i=0;i<3;i++)									
		for(int j=0;j<3;j++)								
			result+=Filter[i*3+j]*Calc_Sum(x+sizex*(i-move)
					,y+sizey*(j-move),x+sizex*(i-move+1)			
					,y+sizey*(j-move+1),imgsum);					
	result=result/((float)sizex*(float)sizey);		
	return result;
}
